Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: ability to add external libs (axios) #990

Merged
merged 15 commits into from
Jul 12, 2018
Merged

Conversation

jeeyyy
Copy link
Contributor

@jeeyyy jeeyyy commented Jul 3, 2018

  • The aim of this PR is to allow for adding of external libraries that are readily available and well tested, to avoid overhead of creating self contained utilities within axe (not re-invent the wheel).
  • The implementation shows adding external library axios (which allows handling network requests), with some generic code written for allowing easier addition of newer libraries in the future.
  • It is achieved by modification to the grunt build process. A new task generate-imports is added as a sub-task with in build step. This prepares the external assets by mounting them on axe.imports object as is (if not UMD wrapped), or after unwrapping UMD resolver and getting the factory to be mounted.
  • axios was chosen over superagent based on this perf test - https://jsperf.com/axios-vs-superagent/

Reviewer checks

Required fields, to be filled out by PR reviewer(s)

  • Follows the commit message policy, appropriate for next version
  • Has documentation updated, a DU ticket, or requires no documentation change
  • Includes new tests, or was unnecessary
  • Code is reviewed for security by: @WilcoFiers

@jeeyyy jeeyyy requested a review from WilcoFiers as a code owner July 3, 2018 23:51
@WilcoFiers
Copy link
Contributor

None of these are things that impact the users, so "feat" and "fix" are inappropriate for this PR.

@WilcoFiers
Copy link
Contributor

Also please don't fill out the checkboxes they are "to be filled out by PR reviewer(s)"

@jeeyyy
Copy link
Contributor Author

jeeyyy commented Jul 4, 2018

@WilcoFiers - In it's true sense this is a new feature, albeit unseen by users. We are creating a feature of being able to add external dependencies. What prefix/ commit standard works better? chore?

@jeeyyy jeeyyy mentioned this pull request Jul 4, 2018
4 tasks
@jeeyyy jeeyyy changed the title feat: ability to add external libs chore: ability to add external libs Jul 4, 2018
@jeeyyy jeeyyy changed the title chore: ability to add external libs chore: ability to add external libs (axios) Jul 4, 2018
Copy link
Contributor

@WilcoFiers WilcoFiers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should add a test to this to ensure axios is included in axe.js.

@jeeyyy
Copy link
Contributor Author

jeeyyy commented Jul 5, 2018

@WilcoFiers - I have added the test for axios. Please squash & merge, so the commit can be prefixed as chore. Thank you.

@jeeyyy jeeyyy dismissed WilcoFiers’s stale review July 5, 2018 08:17

Changes Done. Please review again.

@jeeyyy jeeyyy changed the title chore: ability to add external libs (axios) [WIP] chore: ability to add external libs (axios) Jul 5, 2018
@WilcoFiers
Copy link
Contributor

Recording what we discussed earlier today:

  • Axios will have to be put on axe.import or something so that it can't be overwritten
  • Axios will have to be exposed in axe.source as well so it's still around when we inject axe.

@jeeyyy
Copy link
Contributor Author

jeeyyy commented Jul 6, 2018

Have hit a roadblock with this one now.

  • Attempting to inject an external library into axe.imports namespace, creates side effects like overriding define[] & module.exports from axe. This is seen only when using axe via require as against script inlining which works perfectly.

Mounting the library on axe.imports was done by reading the lib & writing to file, with in axe/core/imports directory, which was later picked up by the build step to concat.

return `
/* global axe, axios */
axe.imports["${library}"] = (function() {
let externalExistence = window["${library}"];
${grunt.file.read(source)} 

if(window["${library}"]) {
	delete window["${library}"];
}
if (externalExistence) {
	window["${library}"] = externalExistence
}
return ${library};
})();
`;

At this juncture, believe there are only a few ways of moving forward with this.

  1. Use the current implementation in this PR, wherein we expose dependencies as globals.
  2. Embrace requirejs for managing dependency and bundling (build step changes).
  3. Introduce progressive typescript, the tsc - compiler as a pre-step to build, which then allows doing import statements in ts files.

Alternative suggestions welcome.

@jeeyyy jeeyyy added info needed More information or research is needed to continue needs discussion More discussion is needed to continue labels Jul 6, 2018
@stephenmathieson
Copy link
Member

@JKODU I think I have a pretty simple solution to the define() and module.exports checks. We can just create a shadowing (scoped) variables tricking Axios' UMD wrapper. For example:

axe.imports.axios = (function () {
  // Clobber these globals, tricking UMD
  var define = undefined
  var module = undefined
  var exports = undefined

  // Keep a copy of the previous Axios global (if set)
  var _axios = window.axios

  ${axios_source_code}

  var axios = window.axios

  // Reset window.axios (if necessary)
  delete window.axios
  if (_axios) {
    window.axios = _axios
  }

  // Return "our" copy of Axios
  return axios
})()

@jeeyyy jeeyyy removed needs discussion More discussion is needed to continue info needed More information or research is needed to continue labels Jul 8, 2018
@jeeyyy jeeyyy changed the title [WIP] chore: ability to add external libs (axios) chore: ability to add external libs (axios) Jul 9, 2018
@jeeyyy
Copy link
Contributor Author

jeeyyy commented Jul 9, 2018

@WilcoFiers - review again

@@ -0,0 +1,3 @@
build/tasks/generate-imports.js
!lib/core/imports/index.js
lib/core/imports/*.js
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll need to add this to gitignore as well.

});

// @wilco - need your input on this, there is no axe.source or equivalent available
// it('should ensure axios source includes axios', function() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

axe.source will be available is module.exports is defined. This test should work in umd-defined.js.

// list of external dependencies,
// which needs to be added to axe.imports object
const LIBS_TO_IMPORT = {
axios: './node_modules/axios/dist/axios.js'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should come from the gruntfile.js rather than live in the task.

processImport(key, LIBS_TO_IMPORT[key]);
});

done();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this function is sync. why did you need this.async()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, initially I was using fs with promises for file read write, but got rid of it. This can go.

/*eslint-env node */
const UglifyJS = require('uglify-js');

module.exports = grunt => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is going to be difficult to maintain without tests preventing regression.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are tests validating axios in umd integration tests. As we add multiple libraries, we can enhance the tests around each library.

return (
/typeof exports/.test(sourceCode) &&
/typeof define/ &&
/typeof module/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to put .test() on these?

@jeeyyy
Copy link
Contributor Author

jeeyyy commented Jul 10, 2018

@WilcoFiers

  • updated umd tests
  • good catch on //.test missing, added
  • migrated library(s) to import to come from Gruntfile.
  • tested generated axe on node, browser, on axe extensions (Worldspace) with custom rule to verify axe.imports.

Please review again.

'Task for generating an axe.imports module with external dependencies.',
function() {
// Convenience method that utilises uglifyjs tree-transformer to unwrap umd module resolver
const removeUMD = new UglifyJS.TreeTransformer(node => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should consider moving this to something like Babel (in the long-term). No need to change now.

}
};

const hasUmdWrapper = sourceCode => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a little scary and seems brittle. I think it's fine for now, since we know Axios has a UMD wrapper, but before we start adding more "imports", we may want to revisit this.

};

const writeLibrary = (libName, factory) => {
const lib = `/* global axe */ axe.imports["${libName}"] = ${factory}`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this ESLint directive, since we're ignoring this file anyway 😉

@@ -0,0 +1,10 @@
/*eslint no-unused-vars: 0*/
/* exported utils */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this directive for?

* @memberof axe
*/

var imports = (axe.imports = {});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need var imports here. Can probably just have axe.imports = {}.

Copy link
Member

@stephenmathieson stephenmathieson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Great work here dude 😄

Copy link
Contributor

@WilcoFiers WilcoFiers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tested this in both Attest-node and the Attest extension to make sure we don't lose Axios somewhere while injecting it. Works like a charm!

@jeeyyy jeeyyy merged commit 0957dab into develop Jul 12, 2018
@jeeyyy jeeyyy deleted the add-external-libs branch July 12, 2018 09:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants