-
Notifications
You must be signed in to change notification settings - Fork 916
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
Replace babel parse with es-module-lexer #208
Replace babel parse with es-module-lexer #208
Conversation
Looks |
Does it work if you import |
"@babel/preset-env": "^7.6.3", | ||
"@babel/traverse": "^7.6.3", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It’s a shame that we don’t gain anything from dropping these since they’re deps of other Babel modules! Still, it brings us closer to dropping Babel altogether which is cool
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea for sure, the benefit here is definitely more speed & stability (a lot less can go wrong when you're just scanning and not also parsing it into a valid AST). But you're right that the total dep count probably hasn't dropped by that much. 🤷♂
lol wow, it looks the issue is that the "require" export is 'dist/lexer.cjs', and not './dist/lexer.cjs'. That's a tricky one: https://nodejs.org/api/esm.html#esm_package_exports https://github.com/guybedford/es-module-lexer/blob/master/package.json#L7-L10 |
Ahh good spot @FredKSchott , thanks for looking into it! I'll open a PR with es-module-lexer now |
}; | ||
export function init(): Promise<void>; | ||
export function parse(code: string): [Array<ImportSpecifier>, Array<string>]; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Maybe if you have time you could contribute these to https://github.com/DefinitelyTyped/DefinitelyTyped, then we can get help from others maintaining this (unless the package author would like to ship these types themselves)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally, that was my plan after I'd got the types nailed for our use case, will definitely be contributing them to DefinitelyTyped
This is awesome! Just tested this out locally in a project and it worked great. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Yea, this is a really tricky one. es-module-lexer is so powerful but that definitely comes at the expense of a fair bit of RegEx / substring
magic.
I think the existing include
test(s) should cover it, but maybe add/update to them to just make sure that they're covering the cases that we're worried about handling correctly:
import a, {b, c as d} from ...
import {b, c as d}, a from ...
import * as ns from
import a, * as ns from
src/scan-imports.ts
Outdated
|
||
const namedImports = (importStatement.match(NAMED_IMPORTS_REGEX) || [, ''])[1] | ||
.split(',') | ||
.map(name => name.trim()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just making sure that this correctly returns ["a"]
for both import {a as b}
and import {a}
.
src/scan-imports.ts
Outdated
} | ||
|
||
const importStatement = code.substring(sStart, sEnd); | ||
const dynamicImport = dynamicImportIndex > -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: it might be nice to push all of this logic into a seperate function as well, so that you could just do something like:
allImports.push(parseImport(importStatement));
@alex-saunders yea, I think it's a bug in Node that that warning is still shown now that the behavior is out from behind a flag. Filed an issue here, lets see if its resolved quickly: nodejs/node#31819 |
b6b4ee1
to
8287312
Compare
@FredKSchott I think I've addressed all your comments and I've added tests to cover the cases you mentioned. |
Just curious when you guys say this is "much faster" and "definitely quicker", if we have a way to prove this or way to ensure we don't have regressions in our tooling performance? I'm pretty curious what kind of boost we are getting by switching to wasm based lexer |
@stramel es-module-lexer comes with benchmarking (https://github.com/guybedford/es-module-lexer#benchmarks) and the results are pretty impressive when compared with babel/full JS AST generation. |
@stramel you're not wrong, there's definitely an "it's wasm so its faster" thing going on in my head 😜. Like @alex-saunders said, their README benchmarks are pretty promising, but that's a good reminder to confirm perf before merging |
@alex-saunders update on nodejs/node#31819: it seems to be their expected behavior that a warning is shown for now, but it looks like there's already a PR to remove the warning in an upcoming version. In the meantime @guybedford removed the export map, so we should be unblocked here / warning should now be gone in the latest version of es-module-lexer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! I left one or two nit comments but feel free to merge after resolving those.
I also checked it out and ran locally on www.pika.dev, which is a fairly complex install (using --include). Not only did everything on the site run as expected, but we saw a 1.5x speedup after switching from Babel to es-module-lexer! (/cc @guybedford thank you!)
Before (with tree-shaking via --optimize)
After (with tree-shaking via --optimize)
After (without --optimize)
src/scan-imports.ts
Outdated
@@ -76,47 +85,41 @@ function parseWebModuleSpecifier(specifier: string): null | string { | |||
return resolvedSpecifier; | |||
} | |||
|
|||
function parseImport(code: string, imp: ImportSpecifier): null | InstallTarget { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love how much it cleaned up the main function to move this out 👍
nit: parseImportStatement()
src/scan-imports.ts
Outdated
@@ -137,7 +140,8 @@ interface ScanImportsParams { | |||
exclude?: glob.IOptions['ignore']; | |||
} | |||
|
|||
export function scanImports({include, exclude}: ScanImportsParams): InstallTarget[] { | |||
export async function scanImports({include, exclude}: ScanImportsParams): Promise<InstallTarget[]> { | |||
await init; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can we rename init
to something like initESModuleLexer
in the import statement?
Just saw the test error, re-installing es-module-lexer to update the package version to latest should fix it. |
Way to go @alex-saunders! 🎉 This is awesome! |
This PR introduces es-module-lexer, and uses it to scan import statements when snowpack is ran with the
--include
flag enabled (replacing the functionality previously provided by @babel/parse and @babel/traverse).I haven't added any new tests as the current suite of
include-*
tests seemed to cover all test cases that I could think of, however there were a couple of requirements I wasn't totally sure about (see my comments) so it might be worth introducing a couple of tests once the requirements are nailed down.The speed increase from using a wasm-based lexer is definitely noticable! However, the information provided by es-module-lexer is a lot more minimal than what we were previously leveraging with babel so I've had to write some fairly rudimentary parsing checks to return what I believe to be the correct information per
InstallTarget
object returned bygetInstallTargetsForFile
es-module-lexer also doesn't ship with any types, nor does it have a
@types
package, so I've included a basic module declaration file under the@types
directory.closes #146