expression replacement - replace `process.env.NODE_ENV`
What's expression replacement
There's need for users that is replacing some expression with another expression in source code.
A typical use case is to replace process.env.NODE_ENV to "production".
Input with typical config
export default {
input: 'src/index.js',
output: {
dir: 'output',
format: 'cjs',
},
plugins: [
define({
replacements: {
'process.env.NODE_ENV': '"production"',
},
}),
],
}
console.log(process.env.NODE_ENV)
would be transformed to
console.log("production")
Thoughts
The processes of this feature in general are
- parse the source code to ast
- parse
process.env.NODE_ENVin'process.env.NODE_ENV': '"production"'toExpression, which we called ittargetnow. - parse
"production"in'process.env.NODE_ENV': '"production"'toExpression, which we called itreplacementnow.
- The
Expressionshould stored in the same arena that used in step1. How we do this? - Oxc need to provide a method to parse something to an
Expression.
- Walk through the ast, in
VisitMut#visit_expression, if someexpr == target, thenstd::mem::replace(&mut expr, replacement.clone()).
expr==targetis a problem, this comparison should ignore theSpan,SymbolIdandReferenceIdreplacement.clone()doesn't seem to works.
In what stages does esbuild and rollup do this? These features should be builtin features provided by oxc.
Oxc already has a work-in-proess transformer and minimizer, ideally we just have to add these features into these two AST passes and let the bundler use these features.
In what stages does esbuild and rollup do this? These features should be builtin features provided by oxc.
That's tricky to say. Rollup support it using the plugin, so rollup itself doesn't provide this feature.
These features should be builtin features provided by oxc.
I think so. But the problems I mentioned above would still exist.
This is why I am interested in how esbuild and rollup solves these problems, even it's inside a plugin.
This is why I am interested in how esbuild and rollup solves these problems, even it's inside a plugin.
It's quite complex, which makes it a challenge for writing it down. Maybe we could discuss it using voice chat.
I think I can figure this out if we reduce the scope to inlining process.env.x and identifiers, as shown in https://github.com/swc-project/swc/blob/94da1241720ed029bc41b6068a9267e2c86347d0/crates/swc_ecma_transforms_optimization/src/inline_globals.rs
@hyf0 Can you give me test case in Rolldown so I can test the whole thing end to end?
@hyf0 Can you give me test case in Rolldown so I can test the whole thing end to end?
I could give one or two cases, but I don't have a test list for this feature.
Maybe the tests of swc could be a start: https://github.com/swc-project/swc/blob/94da1241720ed029bc41b6068a9267e2c86347d0/crates/swc_ecma_transforms_optimization/src/inline_globals.rs#L252-L319.
if we reduce the scope to inlining process.env.x and identifiers
Yeah. This could be start for implementing expression replacement, but in the end we gonna need a general-used expression replacement feature that could almost replace everything not only process.env.xxx.
Tests from wepback: https://github.com/webpack/webpack/blob/4baf1c075d59babd028f8201526cb8c4acfd24a0/test/statsCases/define-plugin/webpack.config.js
https://github.com/rolldown/rolldown/blob/d1a40861b2632acd386c6cb48330df8bc593c0f5/packages/rolldown/rolldown.config.mjs#L41-L45
Skeleton is done in https://github.com/oxc-project/oxc/pull/3803, I'll port esbuild's behaviour and tests.