Skip to content

Avoid parsing require("dep") inside strings in CJS #312

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

Merged
merged 1 commit into from
Jan 12, 2015

Conversation

theefer
Copy link
Contributor

@theefer theefer commented Jan 11, 2015

Fixes #311

Bit of a tedious job as I couldn't find an elegant way to update cjsRequireRegEx to check whether/reject if the match is within a string. The solution I arrived to is to strip all strings from the source if they are not prefixed by (require(). In the absence of lookbehind in JS regex, I have to fallback to an explicit prefix check in the replace function.

I've not restricted this to non-minimised files, since I expect the issue would arise even in minimised files.

The only minor worry is whether this operation is too expensive, but hard to judge without a bit of a performance testing harness.

@guybedford
Copy link
Member

Nice, this seems great.

Yes it could be nice to get some numbers as performance is the primary concern here. It looks like the way things are going is that we could compile modules at install time with the System.registerDynamic wrapper so that this only runs for my custom code that I write in CommonJS and not other installed code.

I'd be happy to take this though soon.

@guybedford
Copy link
Member

I think this covers really well, in due course we can cater to ES6 template literals in a similar way. The hard part is working out if there are any tricky interaction cases between the three - comments within strings, strings within template literals etc. If we can handle each case based on what is sensible for CommonJS requires I think we can keep to the 99% goals pretty well without tokenizing.

Another option would just be to switch to a simple tokenizing system for all this. It would be interesting to see how that compares for performance if we could do all these functions in a single parse.

An earlier version of the loader actually did this stuff with tokenizing -

function removeComments(str) {
.

@theefer
Copy link
Contributor Author

theefer commented Jan 12, 2015

Extracting and caching dependencies offline seems ideal, as IIUC that'd
mean the dynamic detection would really only be applied in "dev" (not for
jspm installed code, not for code from the CDN, not for bundled code)?

That said, given that this PR fixes a live issue that prevents the use of
some packages, would it be acceptable to merge it as a stopgap? I'd
understand reticence if this is going to perceptibly affect performance
though - I could try to run some jsperf tests, eg running that code on a
really large CJS file with and without the fix to measure the impact?

Might have some time this eve.

@guybedford
Copy link
Member

Yes exactly, so we move towards having a dev loader and a minimal lightweight performant production loader.

My only reservation is whether we actually need to be doing tokenizing where strings meet comments. (think "//not a comment").

But we can always add this in at a later stage. Happy to take this for now.

guybedford added a commit that referenced this pull request Jan 12, 2015
Avoid parsing require("dep") inside strings in CJS
@guybedford guybedford merged commit a938f31 into systemjs:master Jan 12, 2015
@theefer
Copy link
Contributor Author

theefer commented Jan 12, 2015

Had a play with some completely non-scientific tests on jsperf:

http://jsperf.com/cjs-string
(running that code on the AngularJS source)

According to these, assuming I've not screwed up the tests (which would be somewhat astonishing), and assuming jsperf gives valid results, both in Chrome and FF the code after my change performs ~25-30% slower (on a beefy Macbook Pro).

Now to put the results in perspective, running this code on the angularjs source takes ~2ms before and ~3ms after the change. Seems generally fast enough, hopefully even on lower spec hardware, that the impact of the change isn't worth worrying about.

@theefer theefer deleted the sc-fix-require-in-string branch January 12, 2015 21:06
@guybedford
Copy link
Member

@theefer thanks, and the AngularJS source is pretty big, so this can still handle hundreds of modules pretty easily it seems.

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.

'require(...)' calls erroneously parsed even within strings in CommonJS
2 participants