-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Feat module umd globals #6717
base: main
Are you sure you want to change the base?
Feat module umd globals #6717
Conversation
- Implementing by reducing globals (no exact mode) - Implementing exact mode by using regex and fallback resolution - Fixing and adding handling of dot only imports to be `_` rather then empty string "" (a change too was made to have it as member and not computed member ) - fixing or updating imports reducing to include Js extension to not do. Just like babel and because it allow importance and exports to work with the same format. Too necessary. - more details on the pr -
- needed for crates/swc_ecma_transforms_module/tests/fixture/common/issue-4456/1/output.umd.ts - there is output.*.js so .ts version make sense
This commit include the changes proted for already existing tests before this PR update. (only 3) - crates/swc_ecma_transforms_module/tests/fixture/common/issue-4456/1/output.umd.ts is due to the handling of dot imports to `_` that was added. - crates/swc_ecma_transforms_module/tests/fixture/common/issue-578/2/output.umd.js crates/swc_ecma_transforms_module/tests/fixture/common/issue-962/output.umd.js Due to the no Js type extension inclusion in reducing for imports (like babel - check PR for details)
- The readme included in that test explain what that is - the behavior follow how babel do it. - See PR for more details (Like what part of the code is responsible for this) -
## testing no exact globals - testing when globals are in reduced format - when globals are not in reduced format - testing when no globals are provided - testing also with the dot imports _ change and no Js type extension inclusion in reducing change. ## exact mode - testing regex matching - testing order precedency and regex resolution fallback - testing no regex matching ## in all the output and mapping is tested to work correctly
cc @magic-akari Can you take a look? |
Sorry for the late reply. It is an oversight which swc behaves differently than babel with respect to file extensions and dot imports. I tested babel locally and have some doubts about some details let js_ext_regex = CachedRegex::new(r#"\.([cm]?[jt]s|[jt]sx)$"#).unwrap(); Do you only deal with some specific suffixes? Examples: import "foo.js";
import "foo.xxx";
import "foo.js.js";
import "foo.js.xxxx"; -> factory(global.foo, global.foo, global.fooJs, global.fooJs); In this PR, you did two things:
For 1. I think it's ok. |
For 2, we need more discussion before merging a PR. |
@magic-akari Thank you! |
@magic-akari @kdy1 First thank you both. And too sorry for being late. I got disconnected and distracted the past few days due to an extra unexpected work and some health issues. I'm more available now.
I did only the javascript one. For the fact of only js, I think it makes sense for UMD. Otherwise, the thing is that those are imports written in the code source. And we do have two cases. People writing them with the import s from "some.container.js"
// and
import s from "some.container" for me should come as the same. If we follow the babel way as you mentioned. In the first it would be Not as relevant but also The transpilation happens on the fly without awareness of all files. And so I guess there is no way to determine when it's meant to be without extension and when it is. I don't know, is there a case where the way I did it would cause a problem? A case where expecting the file to not be a js type extension? And i guess if all make sense and you agree to the elements that are tackled. I guess we can always go with it as it is (js extensions type only). And if a need arises from the community. We can add a hand to provide the extensions matching regex. To support ones beside js. As an option. Personally, I'm not able to see a use case. And I wonder. |
Description
Issue: #6697
Implement
umd globals
mapping features and extra related fixes.Following as best, the babel plugin @babel/plugin-transform-modules-umd
Most things were implemented alike. And there are some important differences and the motivation is explained as well.
features and changes
Reducing function
Extracted the reducing logic in
global_name()
method to a function.And added
js extension no inclusion in reduction
andhandling dot imports
.More details are in the next sections.
handling dot imports and reducing to _
"."
or".."
or../..
... dependencies =>global[""]
--| expect instead |-->global._
as babel do.Change I made:
And outputting
_
as a member and not a computed member["_"]
member vs computed_member => babel does set it as a member
Change I made:
I updated one existing test after that:
Js extensions no inclusion in reduction
change made:
Before:
after:
I followed how babel does it in no exact mode:
Babel does leave it with
Js
extension inexact mode
. But i didn't follow it in that mode. For the reason listed in the motivation.Motivation:
For mapping the lib output you do the following:
Think of the file name
When we include imports:
The
import
is something that is supposed to be added already toglobal
. And compiled by the same process. So the first step oflib module exports
go with filename reducing tofilename stem
. It's without extension. And it should be preserved as well forimports reduction
. So that theimports dependencies
map to the real addedglobals values
.Ex:
if
./lib1.js
is reduced toglobal.lib1Js
then it wouldn't work, becauselib1Js
is never added toglobal
. Onlyglobal.lib1
is. (lib1.umd.js
is included beforeinput.umd.js
). And that's the motivation.And that is what babel does. And the change reflects that.
Updated tests
For this change I updated two existing tests:
Globals mapping main feature and implementation and choices
First and following the babel plugin there is
exact globals mode
andno exact globals mode
.In babel, the
exact mode
is activated by"exactGlobals": true
.I went first with that format. But then I hit a limitation with the
exact mode
handling choice.I opted for doing exact matching using
regex
only. The Babel plugin match usingstring
only.I see it as inflexible. And require more work when the same imports are imported in different modules and have different relative paths ...
The way babel does it. it's to match exactly against the
import declaration
expression. Regex is more flexible and allows a better match for the same module without needing to repeat the matching ...Example:
are different
and
will match the first only.
And
will not match any.
A regex like:
will match both.
Babel exact mode illustration:
Need to be all exact.
I started with
globalExacts
{bool} andglobals
{map}. But then to support the fallback resolution. Regex matched in order. The first that match, is used. I went for two variables.globals
{HashMap<String, String>
type} forno exact mode
. AndexactGlobals
{Vec<(String, Sting)> -[[regexStr, mapStr]]-
type} forexact mode
.So if
none
is provided. Thedefault reduction
is used. As before (plus the new mini changes).If
one
is provided. It will go withexact
orno exact
.No Exact mode
with
globals
{Option<HashMap<String, String>>
} property.Example
the resolution happens as follows:
The same reduce function is used to convert the imports. Babel does it that way.
The differences with babel are:
that babel does reduce the map as well. So mapping
"@themagician/sparkle": "TM.Sparkle"
in babel will map toglobal.TMSparkle
. While in what I did, it would beglobal.TM.Sparkle
. I opted for that because it's simpler. Less processing. And more flexible. People can map to whatever they want. It's there responsibility and again more flexible. Also, it's natural to not use.
and whoever does, should know what he is doing.Babel doesn't reduce the matchers. While our implementation does
All works the same in our implementation => they are reduced first. So they all end up as
lib
.Babel require the users to provide the reduced format directly. Only
"lib": "Lib"
would work in babel for the example above.I opted for this choice. To make it more intuitive and simple for users.
Exact mode
config format:
exactGlobals:
Vec<(String, String)>
Picked as
Array
to allow fallback resolution for regex.Reflected on the precedency test crates/swc_ecma_transforms_module/tests/fixture/common/issue-6697/exact-globals/matching-regex-order-precedency
I opted for
regex
. For the reasons explained above (babel exact string matching, is not flexible, and repetitive to work with ...).The mapping from
Vec<String, String>
toVec<CachedRegex, String>
is done at theBuiltConfig
build step.Info
How to map lib (module export)
every module is exported as
global.<filenameStem> = {}
. Soinput.js
=>global.input = {}
.With no exact mode. just do the following:
Exact mode
Would still work. And multiple regexes go with
first is first to be matched
.In the above:
input.js
=>global.LibSome = {}
Regex
back slash should go in JSON as
\\
. Ex:"^\\.$"
I would write a note about using regex in the doc.
Tests
All features were tested.
Documentation
I have all my notes. I can update it.
To check and questions
Dropping old globals to HashMap<String, Expr>
globals
wasn't used anywhere. And i didn't need the map above that was about mapping toExpr
. So i drop it.Is it ok? should i comment it out only?
no exact mode matcher reduction
As mentioned in no exact mode section and the part about differences with babel. I implemented the matchers (left side) to be reduced. First before matching. Allowing the users to write
lib.js
or./some/lib.js
orlib
all will be reduced to the samelib
. Babel require the reduced format or wouldn't work.Is it ok for what i did (still compatible with babel, but an extra reduction operation)? Or should i just follow the babel plugin on that.
New to rust
I wonder about what i could have not done well. And what should be improved. Or done better.
BREAKING CHANGE:
Not breaking change.
There is things that were changed and provide a differnet js output then before (dot imports, Js extension no inclusion). But none is a breaking change.
Related issue:
#6697