System module format support - #1897
Conversation
|
For now the tests run only against the chunking form tests. These can be expanded fine, just will be a bit of a process. |
|
Can we land #1882 first? Then we can all use it as a base. |
|
@kellyselden this exactly implements the approach in #1882 already, against the code splitting branch as well so you don't need to go through the rebase on that. |
|
If it landed in master first, it would be easier for me to rebase, rather than the entirety of code-splitting. |
|
@kellyselden unfortunately because the |
|
@kellyselden when you asked before about moving forward I suggested rebasing your work to the code splitting PR as a lot of the finalizer stuff and rendering is affected by that. It sounds to me like you are now asking me (indirectly as well?) to rebase the code splitting work to your PR? |
|
@kellyselden how about this - if this PR is delayed for any reason after the code splitting PR lands, we can rebase out the RenderOptions part on top of code splitting directly if it makes your diffs easier. But I'm really hoping this can land alongside the code splitting which will hopefully be in the next day or two. |
e2df971 to
5d13946
Compare
lukastaegert
left a comment
There was a problem hiding this comment.
I'm ok with most of this and agree that this is a HUGE addition as it would basically give as a runtime we can use for older browsers (which leaves us on par with e.g. Webpack in this respect but with noticeably smaller bundles as we never replicate modules—very nice).
I think we definitely need a test for the "starExcludes" case. Also, the need for functional tests of the chunking logic is becoming more and more important as with all the bits of code being inserted here, actually running it seems to be a better guarantee that everything is working than checking "on sight" (cf. "starExcludes" vs. "_starExcludes"). Not sure how much work this will be for the "system" case, though.
As I did no even manage to go through everything @kellyselden submitted, I will postpone the release at least until tomorrow or maybe Wednesday.
| private setDynamicImportResolutions (format: string) { | ||
| const es = format === 'es'; | ||
| let dynamicImportMechanism: DynamicImportMechanism; | ||
| private setDynamicImportResolutions (options: OutputOptions) { |
There was a problem hiding this comment.
({format}: OutputOptions) would reduce the noise further down. Or just leave it as it is?
| initialise (parentScope: Scope): void; | ||
| initialiseAndDeclare (parentScope: Scope, kind: string, init: ExpressionEntity | null): void; | ||
| render(code: MagicString): void; | ||
| render(code: MagicString, opts: RenderOptions): void; |
There was a problem hiding this comment.
If you just call it options instead of opts, it will certainly reduce merge conflicts for @kellyselden. No need for unnecessary abbreviations here.
There was a problem hiding this comment.
(Also, I'm not a huge fan of abbreviations. What seems obvious to yourself at some point does not always seem obvious to everyone else every time especially when code is read out of context. opts is probably not easily misunderstood but it sets precedence for a code style that uses more abbreviations which I am not in favour of due to the reasons outlined above. As you said yourself at some point, people tend to copy the code style they find.)
|
|
||
| const renderOptions: RenderOptions = { | ||
| systemBindings: system, | ||
| importMechanism: undefined |
There was a problem hiding this comment.
Maybe
importMechanism: this.graph.dynamicImport ? this.setDynamicImportResolutions(options) : undefined
or even
importMechanism: this.graph.dynamicImport && this.setDynamicImportResolutions(options)
and removing the next if statement would reduce clutter here
| ) { | ||
| const { dependencies, exports } = chunk.getModuleDeclarations(); | ||
|
|
||
| const deps = dependencies.map(m => `'${getPath(m.id)}'`); |
There was a problem hiding this comment.
deps are actually dependencyIds or dependencyPaths. Would help readability to have a more descriptive name especially since it is only used once much further down.
There was a problem hiding this comment.
Also clashes with the fact that dep further down is not a single item of deps 😉
| if (starExcludes.indexOf('default') === -1) | ||
| starExcludes.push('default'); | ||
| // also include reexport names | ||
| dependencies.forEach(dep => { |
There was a problem hiding this comment.
This is unfortunate naming as dep here shadows dep in the upper context (which is the kind of thing I hope at some point we can have a linter point out) which hurts readability.
As this block is only executed once and otherwise clutters the loop, I would suggestExtracting it e.g. as a getStarExcludes(exports, dependencies) which will also solve the naming conflict and again make the really long function a little more readable 😉
Also it might be worthwhile to consider making starExcludes e.g. a Set which will make all costly .indexOf checks obsolete and can easily be constructed from any array via new Set(someArray) (also being a native data structure, Sets are quite optimised for access). Of course in the end, you would need to write something like Array.from(starExcludes).join(...) and you would loose guaranteed order which in this case does not seem important (but I may be wrong).
There was a problem hiding this comment.
Or of course using an object + Object.keys
| }); | ||
| } | ||
| setter.push(`for (var _$p in module) {`); | ||
| setter.push(`${t}if (!starExcludes[_$p]) _setter[_$p] = module[_$p];`); |
There was a problem hiding this comment.
Also, there is no single test that ever triggers this code. Which is unfortunate as I have the feeling that e.g. starExcludes here should rather be _starExcludes? Might also be an interesting test case for the other formats.
There was a problem hiding this comment.
Good catch. I've included a test for this now.
| fn$1(); | ||
| fn(); | ||
| } | ||
| } exports('default', Main1); |
There was a problem hiding this comment.
Wouldn't this look better if exports was on a new line? It seems to be valid syntax but it sure looks strange.
There was a problem hiding this comment.
The issue I found with this is that adding a new line results in the indentation method of MagicString not applying properly, and I didn't want to get into fixing that. I also thought this seems like some kind of nice shorthand anyway.
5d13946 to
a0aea38
Compare
|
@lukastaegert thanks for the quick review, I've included all the changes and caught an important bug on the reexport testing. As for function tests, ideally yes we should have the SystemJS loading running (which I have been testing here), but I was hesitant to add SystemJS as a dependency just yet for rollup. Will aim to follow up here with more tests. Currently I'm also aiming to get a SystemJS release out at the same time with a 6KB production loader that can work with these use cases while supporting CDN externals of any format (AMD / UMD / System / Global). Will be good to get that on the tests when it's ready I think. |
a0aea38 to
b8b3038
Compare
This provides support for the "system" module format option in Rollup.
It handles full live bindings support identical to the ES spec, including live binding reexport, export *, namespace import support, and dynamic import.
In the process of implementing I've brought through a
RenderOptionsargument to render as in #1882.Because Rollup output is typically done around an application boundary for both single-file and chunk builds the support for hoisting functions through circular references is not provided in the Rollup output. I think this is an adequate tradeoff for the Rollup use cases in general and simplifies the output process nicely as well.
This will be great to test out some chunking workflows with minimal SystemJS builds - so I'd really love if it's possible to land this alongside the chunking work, but let me know what we have time for.