diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 2effe003268..844017adddb 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -853,6 +853,7 @@ export interface RawOptimizationOptions { sideEffects: string usedExports: string providedExports: boolean + innerGraph: boolean realContentHash: boolean } diff --git a/crates/rspack/tests/check.js b/crates/rspack/tests/check.js index 622be8493bd..aa90e51ecfc 100644 --- a/crates/rspack/tests/check.js +++ b/crates/rspack/tests/check.js @@ -3,8 +3,7 @@ const fs = require("fs"); const currentDir = path.resolve(__dirname, "./tree-shaking"); const dirList = fs.readdirSync(currentDir); -const excludeList = ["node_modules"] - +const excludeList = ["node_modules"]; const filteredList = dirList.filter((dir) => { if (dir.startsWith(".")) { @@ -17,19 +16,47 @@ const filteredList = dirList.filter((dir) => { return true; }); -console.log(`total: ${filteredList.length}`) +console.log(`total: ${filteredList.length}`); -const falsePositiveList = [ - 'cjs-export-computed-property', // This one is false positive because webpack will not counted a esm export as unsed in an entry module, the previous implementation follows the esbuild behavior , see https://gist.github.com/IWANABETHATGUY/b41d0f80a558580010276a44b310a473 -] -const failedList = filteredList.filter(item => { - if (falsePositiveList.includes(item)) { - return false; - } - const abPath = path.join(currentDir, item, "snapshot", "snap.diff") - return fs.existsSync(abPath) -}) +const falsePositiveMap = { + "cjs-export-computed-property": + "This one is false positive because webpack will not counted a esm export as unsed in an entry module, the previous implementation follows the esbuild behavior , see https://gist.github.com/IWANABETHATGUY/b41d0f80a558580010276a44b310a473", + basic: "align webpack unused binding behavior", + "context-module-elimated": "align webpack unused binding behavior", + "rollup-unused-called-import": "align webpack unused binding behavior", + "var-function-expr": "align webpack unused binding behavior", + "webpack-innergraph-no-side-effects": "align webpack unused binding behavior", + "side-effects-export-default-expr": "align webpack unused binding behavior" +}; + +const normalizedList = filteredList.map((item) => { + const abPath = path.join(currentDir, item, "snapshot", "snap.diff"); + let status = fs.existsSync(abPath); + return { + name: item, + reason: falsePositiveMap[item], + passed: !status, + }; +}); + +let successedCount = normalizedList.filter((item) => { + return item.passed || !!item.reason; +}).length; + +let fasePositiveCases = normalizedList + .filter((item) => { + return !!item.reason; + }) + .map((item) => { + return `${item.name}: ${item.reason}`; + }); +let failedCases = normalizedList + .filter((item) => !item.passed && !item.reason) + .map((item) => { + return item.name; + }); -console.log(`failed: ${failedList.length}`) -console.log(`passed: ${filteredList.length - failedList.length}`) -console.log('failed list:\n', failedList) +console.log(`failed: ${filteredList.length - successedCount}`); +console.log(`passed: ${successedCount}`); +console.log(`fasePositiveCases: ${fasePositiveCases.length}\n`, fasePositiveCases); +console.log(`failedCases: ${failedCases.length}\n`, failedCases); diff --git a/crates/rspack/tests/fixtures.rs b/crates/rspack/tests/fixtures.rs index a3a2d2f6463..b8170775f92 100644 --- a/crates/rspack/tests/fixtures.rs +++ b/crates/rspack/tests/fixtures.rs @@ -25,7 +25,7 @@ fn samples(fixture_path: PathBuf) { fn tree_shaking(fixture_path: PathBuf) { // For each test case // First test is old version tree shaking snapshot test - test_fixture(&fixture_path, Box::new(|_, _| {}), None); + // test_fixture(&fixture_path, Box::new(|_, _| {}), None); // second test is webpack based tree shaking IS_NEW_TREESHAKING.store(true, Ordering::SeqCst); test_fixture( @@ -34,6 +34,7 @@ fn tree_shaking(fixture_path: PathBuf) { |plugins: &mut Vec, options: &mut CompilerOptions| { options.experiments.rspack_future.new_treeshaking = true; options.optimization.provided_exports = true; + options.optimization.inner_graph = true; options.optimization.used_exports = UsedExportsOption::True; options.builtins.tree_shaking = TreeShaking::False; diff --git a/crates/rspack/tests/tree-shaking/basic/snapshot/new_treeshaking.snap b/crates/rspack/tests/tree-shaking/basic/snapshot/new_treeshaking.snap index 5525f1dd5d2..be6eb84c1b7 100644 --- a/crates/rspack/tests/tree-shaking/basic/snapshot/new_treeshaking.snap +++ b/crates/rspack/tests/tree-shaking/basic/snapshot/new_treeshaking.snap @@ -22,7 +22,7 @@ setTimeout(()=>{ function render() { function test() { const container = document.getElementById("root"); - container.innerHTML = `adddd333:${_lib__WEBPACK_IMPORTED_MODULE_0_.secret}:${_lib__WEBPACK_IMPORTED_MODULE_0_.myanswer}`; + container.innerHTML = `adddd333:${secret}:${myanswer}`; } } if (module.hot?.accept) module.hot.accept((module1)=>{ @@ -39,7 +39,6 @@ __webpack_require__.r(__webpack_exports__); 'use strict'; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { - 'secret': function() { return secret; }, 'myanswer': function() { return myanswer; } }); /* harmony import */var _answer__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./answer */"./answer.js"); diff --git a/crates/rspack/tests/tree-shaking/basic/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/basic/snapshot/snap.diff index 88332af7f14..9ffd6b06128 100644 --- a/crates/rspack/tests/tree-shaking/basic/snapshot/snap.diff +++ b/crates/rspack/tests/tree-shaking/basic/snapshot/snap.diff @@ -5,15 +5,7 @@ function test() { const container = document.getElementById("root"); - container.innerHTML = `adddd333:${/* "./lib" unused */null}:${_lib__WEBPACK_IMPORTED_MODULE_0_.myanswer}`; -+ container.innerHTML = `adddd333:${_lib__WEBPACK_IMPORTED_MODULE_0_.secret}:${_lib__WEBPACK_IMPORTED_MODULE_0_.myanswer}`; ++ container.innerHTML = `adddd333:${secret}:${myanswer}`; } } if (module.hot?.accept) module.hot.accept((module1)=>{ -@@ -39,6 +39,7 @@ - 'use strict'; - __webpack_require__.r(__webpack_exports__); - __webpack_require__.d(__webpack_exports__, { -+ 'secret': function() { return secret; }, - 'myanswer': function() { return myanswer; } - }); - /* harmony import */var _answer__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./answer */"./answer.js"); diff --git a/crates/rspack/tests/tree-shaking/class-extend/snapshot/new_treeshaking.snap b/crates/rspack/tests/tree-shaking/class-extend/snapshot/new_treeshaking.snap index af784057aa7..856485ca0c8 100644 --- a/crates/rspack/tests/tree-shaking/class-extend/snapshot/new_treeshaking.snap +++ b/crates/rspack/tests/tree-shaking/class-extend/snapshot/new_treeshaking.snap @@ -15,7 +15,7 @@ __webpack_require__.d(__webpack_exports__, { } function foo() { return { - OriginLib: _lib__WEBPACK_IMPORTED_MODULE_0_.Lib + OriginLib }; } const v = _lib__WEBPACK_IMPORTED_MODULE_0_.value; diff --git a/crates/rspack/tests/tree-shaking/class-extend/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/class-extend/snapshot/snap.diff index 1665d4d4074..623457cd02f 100644 --- a/crates/rspack/tests/tree-shaking/class-extend/snapshot/snap.diff +++ b/crates/rspack/tests/tree-shaking/class-extend/snapshot/snap.diff @@ -10,7 +10,7 @@ function foo() { return { - OriginLib: /* "./lib" unused */null -+ OriginLib: _lib__WEBPACK_IMPORTED_MODULE_0_.Lib ++ OriginLib }; } const v = _lib__WEBPACK_IMPORTED_MODULE_0_.value; diff --git a/crates/rspack/tests/tree-shaking/context-module-elimated/snapshot/new_treeshaking.snap b/crates/rspack/tests/tree-shaking/context-module-elimated/snapshot/new_treeshaking.snap index 4bc90088ccb..a600e1cbcb6 100644 --- a/crates/rspack/tests/tree-shaking/context-module-elimated/snapshot/new_treeshaking.snap +++ b/crates/rspack/tests/tree-shaking/context-module-elimated/snapshot/new_treeshaking.snap @@ -3,66 +3,14 @@ source: crates/rspack_testing/src/run_fixture.rs --- ```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./child/child/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'value': function() { return value; } -}); - const value = "dynamic"; -}, -"./child/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'value': function() { return value; } -}); - const value = "dynamic"; -}, -"./child Sync recursive ^\\.\\/.*\\.js$": function (module, exports, __webpack_require__) { -var map = {"./child/index.js": "./child/child/index.js","./index.js": "./child/index.js",}; -function webpackContext(req) { -var id = webpackContextResolve(req); - -return __webpack_require__(id); - -} -function webpackContextResolve(req) { - - if(!__webpack_require__.o(map, req)) { - var e = new Error("Cannot find module '" + req + "'"); - e.code = 'MODULE_NOT_FOUND'; - throw e; - } - return map[req]; - -} -webpackContext.id = '"./child Sync recursive ^\\.\\/.*\\.js$"'; - - webpackContext.keys = function webpackContextKeys() { - return Object.keys(map); - }; - webpackContext.resolve = webpackContextResolve; - module.exports = webpackContext; - }, "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -/* harmony import */var _lib_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./lib.js */"./lib.js"); function test() { - _lib_js__WEBPACK_IMPORTED_MODULE_0_.a; + a; } }, -"./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'a': function() { return a; } -}); - const a = ""; -__webpack_require__(/* ./child */"./child Sync recursive ^\\.\\/.*\\.js$")((`./child/${a}.js`).replace('./child/', './')); -}, },function(__webpack_require__) { var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } diff --git a/crates/rspack/tests/tree-shaking/context-module-elimated/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/context-module-elimated/snapshot/snap.diff index 8e9dcf8147d..8fec2547e09 100644 --- a/crates/rspack/tests/tree-shaking/context-module-elimated/snapshot/snap.diff +++ b/crates/rspack/tests/tree-shaking/context-module-elimated/snapshot/snap.diff @@ -1,70 +1,11 @@ --- expected +++ actual -@@ -3,14 +3,66 @@ - --- - ```js title=main.js - (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -+"./child/child/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -+'use strict'; -+__webpack_require__.r(__webpack_exports__); -+__webpack_require__.d(__webpack_exports__, { -+ 'value': function() { return value; } -+}); -+ const value = "dynamic"; -+}, -+"./child/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -+'use strict'; -+__webpack_require__.r(__webpack_exports__); -+__webpack_require__.d(__webpack_exports__, { -+ 'value': function() { return value; } -+}); -+ const value = "dynamic"; -+}, -+"./child Sync recursive ^\\.\\/.*\\.js$": function (module, exports, __webpack_require__) { -+var map = {"./child/index.js": "./child/child/index.js","./index.js": "./child/index.js",}; -+function webpackContext(req) { -+var id = webpackContextResolve(req); -+ -+return __webpack_require__(id); -+ -+} -+function webpackContextResolve(req) { -+ -+ if(!__webpack_require__.o(map, req)) { -+ var e = new Error("Cannot find module '" + req + "'"); -+ e.code = 'MODULE_NOT_FOUND'; -+ throw e; -+ } -+ return map[req]; -+ -+} -+webpackContext.id = '"./child Sync recursive ^\\.\\/.*\\.js$"'; -+ -+ webpackContext.keys = function webpackContextKeys() { -+ return Object.keys(map); -+ }; -+ webpackContext.resolve = webpackContextResolve; -+ module.exports = webpackContext; -+ }, - "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { - 'use strict'; +@@ -8,7 +8,7 @@ __webpack_require__.r(__webpack_exports__); -+/* harmony import */var _lib_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./lib.js */"./lib.js"); function test() { - /* "./lib.js" unused */null; -+ _lib_js__WEBPACK_IMPORTED_MODULE_0_.a; ++ a; } }, -+"./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -+'use strict'; -+__webpack_require__.r(__webpack_exports__); -+__webpack_require__.d(__webpack_exports__, { -+ 'a': function() { return a; } -+}); -+ const a = ""; -+__webpack_require__(/* ./child */"./child Sync recursive ^\\.\\/.*\\.js$")((`./child/${a}.js`).replace('./child/', './')); -+}, - },function(__webpack_require__) { - var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } diff --git a/crates/rspack/tests/tree-shaking/rollup-unused-called-import/snapshot/new_treeshaking.snap b/crates/rspack/tests/tree-shaking/rollup-unused-called-import/snapshot/new_treeshaking.snap index efd6bf481f5..e8808afeb50 100644 --- a/crates/rspack/tests/tree-shaking/rollup-unused-called-import/snapshot/new_treeshaking.snap +++ b/crates/rspack/tests/tree-shaking/rollup-unused-called-import/snapshot/new_treeshaking.snap @@ -6,9 +6,6 @@ source: crates/rspack_testing/src/run_fixture.rs "./dead.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } -}); function __WEBPACK_DEFAULT_EXPORT__(){ return "dead"; } @@ -25,7 +22,7 @@ function __WEBPACK_DEFAULT_EXPORT__(){ return "foo"; } function foodead() { - return "foo" + (0, _dead__WEBPACK_IMPORTED_MODULE_0_["default"])(); + return "foo" + dead(); } }, "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { diff --git a/crates/rspack/tests/tree-shaking/rollup-unused-called-import/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/rollup-unused-called-import/snapshot/snap.diff index ea0a1343b8d..3be578b742d 100644 --- a/crates/rspack/tests/tree-shaking/rollup-unused-called-import/snapshot/snap.diff +++ b/crates/rspack/tests/tree-shaking/rollup-unused-called-import/snapshot/snap.diff @@ -1,21 +1,11 @@ --- expected +++ actual -@@ -6,6 +6,9 @@ - "./dead.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { - 'use strict'; - __webpack_require__.r(__webpack_exports__); -+__webpack_require__.d(__webpack_exports__, { -+ 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } -+}); - function __WEBPACK_DEFAULT_EXPORT__(){ - return "dead"; - } -@@ -22,7 +25,7 @@ +@@ -22,7 +22,7 @@ return "foo"; } function foodead() { - return "foo" + /* "./dead" unused */null(); -+ return "foo" + (0, _dead__WEBPACK_IMPORTED_MODULE_0_["default"])(); ++ return "foo" + dead(); } }, "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { diff --git a/crates/rspack/tests/tree-shaking/ts-target-es5/snapshot/new_treeshaking.snap b/crates/rspack/tests/tree-shaking/ts-target-es5/snapshot/new_treeshaking.snap index 1e2d5450a5b..6299a6f90ee 100644 --- a/crates/rspack/tests/tree-shaking/ts-target-es5/snapshot/new_treeshaking.snap +++ b/crates/rspack/tests/tree-shaking/ts-target-es5/snapshot/new_treeshaking.snap @@ -3,492 +3,17 @@ source: crates/rspack_testing/src/run_fixture.rs --- ```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"../../../../../node_modules/@swc/helpers/esm/_async_to_generator.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - '_': function() { return _async_to_generator; } -}); -function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error) { - reject(error); - return; - } - if (info.done) resolve(value); - else Promise.resolve(value).then(_next, _throw); -} - function _async_to_generator(fn) { - return function() { - var self = this, args = arguments; - return new Promise(function(resolve, reject) { - var gen = fn.apply(self, args); - function _next(value) { - asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); - } - function _throw(err) { - asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); - } - _next(undefined); - }); - }; -} - -}, -"../../../../../node_modules/@swc/helpers/esm/_ts_generator.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - '_': function() { return tslib__WEBPACK_IMPORTED_MODULE_0_.__generator; } -}); -/* harmony import */var tslib__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* tslib */"../../../../../node_modules/tslib/tslib.es6.js"); - -}, -"../../../../../node_modules/tslib/tslib.es6.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/****************************************************************************** -Copyright (c) Microsoft Corporation. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. -***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { - extendStatics = Object.setPrototypeOf || ({ - __proto__: [] - }) instanceof Array && function(d, b) { - d.__proto__ = b; - } || function(d, b) { - for(var p in b)if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; - }; - return extendStatics(d, b); -}; - function __extends(d, b) { - if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); - extendStatics(d, b); - function __() { - this.constructor = d; - } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); -} - var __assign = function() { - __assign = Object.assign || function __assign(t) { - for(var s, i = 1, n = arguments.length; i < n; i++){ - s = arguments[i]; - for(var p in s)if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; - } - return t; - }; - return __assign.apply(this, arguments); -}; - function __rest(s, e) { - var t = {}; - for(var p in s)if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (s != null && typeof Object.getOwnPropertySymbols === "function") { - for(var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++)if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; - } - return t; -} - function __decorate(decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -} - function __param(paramIndex, decorator) { - return function(target, key) { - decorator(target, key, paramIndex); - }; -} - function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { - function accept(f) { - if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); - return f; - } - var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; - var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; - var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); - var _, done = false; - for(var i = decorators.length - 1; i >= 0; i--){ - var context = {}; - for(var p in contextIn)context[p] = p === "access" ? {} : contextIn[p]; - for(var p in contextIn.access)context.access[p] = contextIn.access[p]; - context.addInitializer = function(f) { - if (done) throw new TypeError("Cannot add initializers after decoration has completed"); - extraInitializers.push(accept(f || null)); - }; - var result = (0, decorators[i])(kind === "accessor" ? { - get: descriptor.get, - set: descriptor.set - } : descriptor[key], context); - if (kind === "accessor") { - if (result === void 0) continue; - if (result === null || typeof result !== "object") throw new TypeError("Object expected"); - if (_ = accept(result.get)) descriptor.get = _; - if (_ = accept(result.set)) descriptor.set = _; - if (_ = accept(result.init)) initializers.push(_); - } else if (_ = accept(result)) { - if (kind === "field") initializers.push(_); - else descriptor[key] = _; - } - } - if (target) Object.defineProperty(target, contextIn.name, descriptor); - done = true; -} - function __runInitializers(thisArg, initializers, value) { - var useValue = arguments.length > 2; - for(var i = 0; i < initializers.length; i++)value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); - return useValue ? value : void 0; -} - function __propKey(x) { - return typeof x === "symbol" ? x : "".concat(x); -} - function __setFunctionName(f, name, prefix) { - if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : ""; - return Object.defineProperty(f, "name", { - configurable: true, - value: prefix ? "".concat(prefix, " ", name) : name - }); -} - function __metadata(metadataKey, metadataValue) { - if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); -} - function __awaiter(thisArg, _arguments, P, generator) { - function adopt(value) { - return value instanceof P ? value : new P(function(resolve) { - resolve(value); - }); - } - return new (P || (P = Promise))(function(resolve, reject) { - function fulfilled(value) { - try { - step(generator.next(value)); - } catch (e) { - reject(e); - } - } - function rejected(value) { - try { - step(generator["throw"](value)); - } catch (e) { - reject(e); - } - } - function step(result) { - result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); - } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -} - function __generator(thisArg, body) { - var _ = { - label: 0, - sent: function() { - if (t[0] & 1) throw t[1]; - return t[1]; - }, - trys: [], - ops: [] - }, f, y, t, g; - return g = { - next: verb(0), - "throw": verb(1), - "return": verb(2) - }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { - return this; - }), g; - function verb(n) { - return function(v) { - return step([ - n, - v - ]); - }; - } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while(g && (g = 0, op[0] && (_ = 0)), _)try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [ - op[0] & 2, - t.value - ]; - switch(op[0]){ - case 0: - case 1: - t = op; - break; - case 4: - _.label++; - return { - value: op[1], - done: false - }; - case 5: - _.label++; - y = op[1]; - op = [ - 0 - ]; - continue; - case 7: - op = _.ops.pop(); - _.trys.pop(); - continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { - _ = 0; - continue; - } - if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) { - _.label = op[1]; - break; - } - if (op[0] === 6 && _.label < t[1]) { - _.label = t[1]; - t = op; - break; - } - if (t && _.label < t[2]) { - _.label = t[2]; - _.ops.push(op); - break; - } - if (t[2]) _.ops.pop(); - _.trys.pop(); - continue; - } - op = body.call(thisArg, _); - } catch (e) { - op = [ - 6, - e - ]; - y = 0; - } finally{ - f = t = 0; - } - if (op[0] & 5) throw op[1]; - return { - value: op[0] ? op[1] : void 0, - done: true - }; - } -} - var __createBinding = Object.create ? function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) desc = { - enumerable: true, - get: function() { - return m[k]; - } - }; - Object.defineProperty(o, k2, desc); -} : function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -}; - function __exportStar(m, o) { - for(var p in m)if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p); -} - function __values(o) { - var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; - if (m) return m.call(o); - if (o && typeof o.length === "number") return { - next: function() { - if (o && i >= o.length) o = void 0; - return { - value: o && o[i++], - done: !o - }; - } - }; - throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); -} - function __read(o, n) { - var m = typeof Symbol === "function" && o[Symbol.iterator]; - if (!m) return o; - var i = m.call(o), r, ar = [], e; - try { - while((n === void 0 || n-- > 0) && !(r = i.next()).done)ar.push(r.value); - } catch (error) { - e = { - error: error - }; - } finally{ - try { - if (r && !r.done && (m = i["return"])) m.call(i); - } finally{ - if (e) throw e.error; - } - } - return ar; -} -/** @deprecated */ function __spread() { - for(var ar = [], i = 0; i < arguments.length; i++)ar = ar.concat(__read(arguments[i])); - return ar; -} -/** @deprecated */ function __spreadArrays() { - for(var s = 0, i = 0, il = arguments.length; i < il; i++)s += arguments[i].length; - for(var r = Array(s), k = 0, i = 0; i < il; i++)for(var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)r[k] = a[j]; - return r; -} - function __spreadArray(to, from, pack) { - if (pack || arguments.length === 2) { - for(var i = 0, l = from.length, ar; i < l; i++)if (ar || !(i in from)) { - if (!ar) ar = Array.prototype.slice.call(from, 0, i); - ar[i] = from[i]; - } - } - return to.concat(ar || Array.prototype.slice.call(from)); -} - function __await(v) { - return this instanceof __await ? (this.v = v, this) : new __await(v); -} - function __asyncGenerator(thisArg, _arguments, generator) { - if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); - var g = generator.apply(thisArg, _arguments || []), i, q = []; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() { - return this; - }, i; - function verb(n) { - if (g[n]) i[n] = function(v) { - return new Promise(function(a, b) { - q.push([ - n, - v, - a, - b - ]) > 1 || resume(n, v); - }); - }; - } - function resume(n, v) { - try { - step(g[n](v)); - } catch (e) { - settle(q[0][3], e); - } - } - function step(r) { - r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); - } - function fulfill(value) { - resume("next", value); - } - function reject(value) { - resume("throw", value); - } - function settle(f, v) { - if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); - } -} - function __asyncDelegator(o) { - var i, p; - return i = {}, verb("next"), verb("throw", function(e) { - throw e; - }), verb("return"), i[Symbol.iterator] = function() { - return this; - }, i; - function verb(n, f) { - i[n] = o[n] ? function(v) { - return (p = !p) ? { - value: __await(o[n](v)), - done: false - } : f ? f(v) : v; - } : f; - } -} - function __asyncValues(o) { - if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); - var m = o[Symbol.asyncIterator], i; - return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() { - return this; - }, i); - function verb(n) { - i[n] = o[n] && function(v) { - return new Promise(function(resolve, reject) { - v = o[n](v), settle(resolve, reject, v.done, v.value); - }); - }; - } - function settle(resolve, reject, d, v) { - Promise.resolve(v).then(function(v) { - resolve({ - value: v, - done: d - }); - }, reject); - } -} - function __makeTemplateObject(cooked, raw) { - if (Object.defineProperty) Object.defineProperty(cooked, "raw", { - value: raw - }); - else cooked.raw = raw; - return cooked; -} -var __setModuleDefault = Object.create ? function(o, v) { - Object.defineProperty(o, "default", { - enumerable: true, - value: v - }); -} : function(o, v) { - o["default"] = v; -}; - function __importStar(mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) { - for(var k in mod)if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - } - __setModuleDefault(result, mod); - return result; -} - function __importDefault(mod) { - return mod && mod.__esModule ? mod : { - default: mod - }; -} - function __classPrivateFieldGet(receiver, state, kind, f) { - if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); - if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); - return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); -} - function __classPrivateFieldSet(receiver, state, value, kind, f) { - if (kind === "m") throw new TypeError("Private method is not writable"); - if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); - if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); - return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value; -} - function __classPrivateFieldIn(state, receiver) { - if (receiver === null || typeof receiver !== "object" && typeof receiver !== "function") throw new TypeError("Cannot use 'in' operator on non-object"); - return typeof state === "function" ? receiver === state : state.has(receiver); -} -}, "./index.ts": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -/* harmony import */var _swc_helpers_async_to_generator__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* @swc/helpers/_/_async_to_generator */"../../../../../node_modules/@swc/helpers/esm/_async_to_generator.js"); -/* harmony import */var _swc_helpers_ts_generator__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* @swc/helpers/_/_ts_generator */"../../../../../node_modules/@swc/helpers/esm/_ts_generator.js"); function test() { return _test.apply(this, arguments); } function _test() { - _test = (0, _swc_helpers_async_to_generator__WEBPACK_IMPORTED_MODULE_0_._)(function() { - return (0, _swc_helpers_ts_generator__WEBPACK_IMPORTED_MODULE_1_._)(this, function(_state) { + _test = _async_to_generator(function() { + return _ts_generator(this, function(_state) { return [ 2 ]; diff --git a/crates/rspack/tests/tree-shaking/ts-target-es5/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/ts-target-es5/snapshot/snap.diff index bc740092764..35655c03d56 100644 --- a/crates/rspack/tests/tree-shaking/ts-target-es5/snapshot/snap.diff +++ b/crates/rspack/tests/tree-shaking/ts-target-es5/snapshot/snap.diff @@ -1,22 +1,503 @@ --- expected +++ actual -@@ -49,9 +49,6 @@ - "../../../../../node_modules/tslib/tslib.es6.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { - 'use strict'; - __webpack_require__.r(__webpack_exports__); +@@ -3,498 +3,17 @@ + --- + ```js title=main.js + (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { +-"../../../../../node_modules/@swc/helpers/esm/_async_to_generator.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- '_': function() { return _async_to_generator; } +-}); +-function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { +- try { +- var info = gen[key](arg); +- var value = info.value; +- } catch (error) { +- reject(error); +- return; +- } +- if (info.done) resolve(value); +- else Promise.resolve(value).then(_next, _throw); +-} +- function _async_to_generator(fn) { +- return function() { +- var self = this, args = arguments; +- return new Promise(function(resolve, reject) { +- var gen = fn.apply(self, args); +- function _next(value) { +- asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); +- } +- function _throw(err) { +- asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); +- } +- _next(undefined); +- }); +- }; +-} +- +-}, +-"../../../../../node_modules/@swc/helpers/esm/_ts_generator.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- '_': function() { return tslib__WEBPACK_IMPORTED_MODULE_0_.__generator; } +-}); +-/* harmony import */var tslib__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* tslib */"../../../../../node_modules/tslib/tslib.es6.js"); +- +-}, +-"../../../../../node_modules/tslib/tslib.es6.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - '__generator': function() { return __generator; } -}); - /****************************************************************************** - Copyright (c) Microsoft Corporation. - -@@ -482,9 +479,6 @@ +-/****************************************************************************** +-Copyright (c) Microsoft Corporation. +- +-Permission to use, copy, modify, and/or distribute this software for any +-purpose with or without fee is hereby granted. +- +-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +-AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +-PERFORMANCE OF THIS SOFTWARE. +-***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { +- extendStatics = Object.setPrototypeOf || ({ +- __proto__: [] +- }) instanceof Array && function(d, b) { +- d.__proto__ = b; +- } || function(d, b) { +- for(var p in b)if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; +- }; +- return extendStatics(d, b); +-}; +- function __extends(d, b) { +- if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); +- extendStatics(d, b); +- function __() { +- this.constructor = d; +- } +- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +-} +- var __assign = function() { +- __assign = Object.assign || function __assign(t) { +- for(var s, i = 1, n = arguments.length; i < n; i++){ +- s = arguments[i]; +- for(var p in s)if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; +- } +- return t; +- }; +- return __assign.apply(this, arguments); +-}; +- function __rest(s, e) { +- var t = {}; +- for(var p in s)if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; +- if (s != null && typeof Object.getOwnPropertySymbols === "function") { +- for(var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++)if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; +- } +- return t; +-} +- function __decorate(decorators, target, key, desc) { +- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; +- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); +- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; +- return c > 3 && r && Object.defineProperty(target, key, r), r; +-} +- function __param(paramIndex, decorator) { +- return function(target, key) { +- decorator(target, key, paramIndex); +- }; +-} +- function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { +- function accept(f) { +- if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); +- return f; +- } +- var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; +- var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; +- var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); +- var _, done = false; +- for(var i = decorators.length - 1; i >= 0; i--){ +- var context = {}; +- for(var p in contextIn)context[p] = p === "access" ? {} : contextIn[p]; +- for(var p in contextIn.access)context.access[p] = contextIn.access[p]; +- context.addInitializer = function(f) { +- if (done) throw new TypeError("Cannot add initializers after decoration has completed"); +- extraInitializers.push(accept(f || null)); +- }; +- var result = (0, decorators[i])(kind === "accessor" ? { +- get: descriptor.get, +- set: descriptor.set +- } : descriptor[key], context); +- if (kind === "accessor") { +- if (result === void 0) continue; +- if (result === null || typeof result !== "object") throw new TypeError("Object expected"); +- if (_ = accept(result.get)) descriptor.get = _; +- if (_ = accept(result.set)) descriptor.set = _; +- if (_ = accept(result.init)) initializers.push(_); +- } else if (_ = accept(result)) { +- if (kind === "field") initializers.push(_); +- else descriptor[key] = _; +- } +- } +- if (target) Object.defineProperty(target, contextIn.name, descriptor); +- done = true; +-} +- function __runInitializers(thisArg, initializers, value) { +- var useValue = arguments.length > 2; +- for(var i = 0; i < initializers.length; i++)value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); +- return useValue ? value : void 0; +-} +- function __propKey(x) { +- return typeof x === "symbol" ? x : "".concat(x); +-} +- function __setFunctionName(f, name, prefix) { +- if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : ""; +- return Object.defineProperty(f, "name", { +- configurable: true, +- value: prefix ? "".concat(prefix, " ", name) : name +- }); +-} +- function __metadata(metadataKey, metadataValue) { +- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); +-} +- function __awaiter(thisArg, _arguments, P, generator) { +- function adopt(value) { +- return value instanceof P ? value : new P(function(resolve) { +- resolve(value); +- }); +- } +- return new (P || (P = Promise))(function(resolve, reject) { +- function fulfilled(value) { +- try { +- step(generator.next(value)); +- } catch (e) { +- reject(e); +- } +- } +- function rejected(value) { +- try { +- step(generator["throw"](value)); +- } catch (e) { +- reject(e); +- } +- } +- function step(result) { +- result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); +- } +- step((generator = generator.apply(thisArg, _arguments || [])).next()); +- }); +-} +- function __generator(thisArg, body) { +- var _ = { +- label: 0, +- sent: function() { +- if (t[0] & 1) throw t[1]; +- return t[1]; +- }, +- trys: [], +- ops: [] +- }, f, y, t, g; +- return g = { +- next: verb(0), +- "throw": verb(1), +- "return": verb(2) +- }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { +- return this; +- }), g; +- function verb(n) { +- return function(v) { +- return step([ +- n, +- v +- ]); +- }; +- } +- function step(op) { +- if (f) throw new TypeError("Generator is already executing."); +- while(g && (g = 0, op[0] && (_ = 0)), _)try { +- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; +- if (y = 0, t) op = [ +- op[0] & 2, +- t.value +- ]; +- switch(op[0]){ +- case 0: +- case 1: +- t = op; +- break; +- case 4: +- _.label++; +- return { +- value: op[1], +- done: false +- }; +- case 5: +- _.label++; +- y = op[1]; +- op = [ +- 0 +- ]; +- continue; +- case 7: +- op = _.ops.pop(); +- _.trys.pop(); +- continue; +- default: +- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { +- _ = 0; +- continue; +- } +- if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) { +- _.label = op[1]; +- break; +- } +- if (op[0] === 6 && _.label < t[1]) { +- _.label = t[1]; +- t = op; +- break; +- } +- if (t && _.label < t[2]) { +- _.label = t[2]; +- _.ops.push(op); +- break; +- } +- if (t[2]) _.ops.pop(); +- _.trys.pop(); +- continue; +- } +- op = body.call(thisArg, _); +- } catch (e) { +- op = [ +- 6, +- e +- ]; +- y = 0; +- } finally{ +- f = t = 0; +- } +- if (op[0] & 5) throw op[1]; +- return { +- value: op[0] ? op[1] : void 0, +- done: true +- }; +- } +-} +- var __createBinding = Object.create ? function(o, m, k, k2) { +- if (k2 === undefined) k2 = k; +- var desc = Object.getOwnPropertyDescriptor(m, k); +- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) desc = { +- enumerable: true, +- get: function() { +- return m[k]; +- } +- }; +- Object.defineProperty(o, k2, desc); +-} : function(o, m, k, k2) { +- if (k2 === undefined) k2 = k; +- o[k2] = m[k]; +-}; +- function __exportStar(m, o) { +- for(var p in m)if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p); +-} +- function __values(o) { +- var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; +- if (m) return m.call(o); +- if (o && typeof o.length === "number") return { +- next: function() { +- if (o && i >= o.length) o = void 0; +- return { +- value: o && o[i++], +- done: !o +- }; +- } +- }; +- throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); +-} +- function __read(o, n) { +- var m = typeof Symbol === "function" && o[Symbol.iterator]; +- if (!m) return o; +- var i = m.call(o), r, ar = [], e; +- try { +- while((n === void 0 || n-- > 0) && !(r = i.next()).done)ar.push(r.value); +- } catch (error) { +- e = { +- error: error +- }; +- } finally{ +- try { +- if (r && !r.done && (m = i["return"])) m.call(i); +- } finally{ +- if (e) throw e.error; +- } +- } +- return ar; +-} +-/** @deprecated */ function __spread() { +- for(var ar = [], i = 0; i < arguments.length; i++)ar = ar.concat(__read(arguments[i])); +- return ar; +-} +-/** @deprecated */ function __spreadArrays() { +- for(var s = 0, i = 0, il = arguments.length; i < il; i++)s += arguments[i].length; +- for(var r = Array(s), k = 0, i = 0; i < il; i++)for(var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)r[k] = a[j]; +- return r; +-} +- function __spreadArray(to, from, pack) { +- if (pack || arguments.length === 2) { +- for(var i = 0, l = from.length, ar; i < l; i++)if (ar || !(i in from)) { +- if (!ar) ar = Array.prototype.slice.call(from, 0, i); +- ar[i] = from[i]; +- } +- } +- return to.concat(ar || Array.prototype.slice.call(from)); +-} +- function __await(v) { +- return this instanceof __await ? (this.v = v, this) : new __await(v); +-} +- function __asyncGenerator(thisArg, _arguments, generator) { +- if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); +- var g = generator.apply(thisArg, _arguments || []), i, q = []; +- return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() { +- return this; +- }, i; +- function verb(n) { +- if (g[n]) i[n] = function(v) { +- return new Promise(function(a, b) { +- q.push([ +- n, +- v, +- a, +- b +- ]) > 1 || resume(n, v); +- }); +- }; +- } +- function resume(n, v) { +- try { +- step(g[n](v)); +- } catch (e) { +- settle(q[0][3], e); +- } +- } +- function step(r) { +- r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); +- } +- function fulfill(value) { +- resume("next", value); +- } +- function reject(value) { +- resume("throw", value); +- } +- function settle(f, v) { +- if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); +- } +-} +- function __asyncDelegator(o) { +- var i, p; +- return i = {}, verb("next"), verb("throw", function(e) { +- throw e; +- }), verb("return"), i[Symbol.iterator] = function() { +- return this; +- }, i; +- function verb(n, f) { +- i[n] = o[n] ? function(v) { +- return (p = !p) ? { +- value: __await(o[n](v)), +- done: false +- } : f ? f(v) : v; +- } : f; +- } +-} +- function __asyncValues(o) { +- if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); +- var m = o[Symbol.asyncIterator], i; +- return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() { +- return this; +- }, i); +- function verb(n) { +- i[n] = o[n] && function(v) { +- return new Promise(function(resolve, reject) { +- v = o[n](v), settle(resolve, reject, v.done, v.value); +- }); +- }; +- } +- function settle(resolve, reject, d, v) { +- Promise.resolve(v).then(function(v) { +- resolve({ +- value: v, +- done: d +- }); +- }, reject); +- } +-} +- function __makeTemplateObject(cooked, raw) { +- if (Object.defineProperty) Object.defineProperty(cooked, "raw", { +- value: raw +- }); +- else cooked.raw = raw; +- return cooked; +-} +-var __setModuleDefault = Object.create ? function(o, v) { +- Object.defineProperty(o, "default", { +- enumerable: true, +- value: v +- }); +-} : function(o, v) { +- o["default"] = v; +-}; +- function __importStar(mod) { +- if (mod && mod.__esModule) return mod; +- var result = {}; +- if (mod != null) { +- for(var k in mod)if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); +- } +- __setModuleDefault(result, mod); +- return result; +-} +- function __importDefault(mod) { +- return mod && mod.__esModule ? mod : { +- default: mod +- }; +-} +- function __classPrivateFieldGet(receiver, state, kind, f) { +- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); +- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); +- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +-} +- function __classPrivateFieldSet(receiver, state, value, kind, f) { +- if (kind === "m") throw new TypeError("Private method is not writable"); +- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); +- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); +- return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value; +-} +- function __classPrivateFieldIn(state, receiver) { +- if (receiver === null || typeof receiver !== "object" && typeof receiver !== "function") throw new TypeError("Cannot use 'in' operator on non-object"); +- return typeof state === "function" ? receiver === state : state.has(receiver); +-} +-}, "./index.ts": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'test': function() { return test; } -}); - /* harmony import */var _swc_helpers_async_to_generator__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* @swc/helpers/_/_async_to_generator */"../../../../../node_modules/@swc/helpers/esm/_async_to_generator.js"); - /* harmony import */var _swc_helpers_ts_generator__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* @swc/helpers/_/_ts_generator */"../../../../../node_modules/@swc/helpers/esm/_ts_generator.js"); +-/* harmony import */var _swc_helpers_async_to_generator__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* @swc/helpers/_/_async_to_generator */"../../../../../node_modules/@swc/helpers/esm/_async_to_generator.js"); +-/* harmony import */var _swc_helpers_ts_generator__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* @swc/helpers/_/_ts_generator */"../../../../../node_modules/@swc/helpers/esm/_ts_generator.js"); + + function test() { + return _test.apply(this, arguments); + } + function _test() { +- _test = (0, _swc_helpers_async_to_generator__WEBPACK_IMPORTED_MODULE_0_._)(function() { +- return (0, _swc_helpers_ts_generator__WEBPACK_IMPORTED_MODULE_1_._)(this, function(_state) { ++ _test = _async_to_generator(function() { ++ return _ts_generator(this, function(_state) { + return [ + 2 + ]; diff --git a/crates/rspack/tests/tree-shaking/var-function-expr/snapshot/new_treeshaking.snap b/crates/rspack/tests/tree-shaking/var-function-expr/snapshot/new_treeshaking.snap index 1198b349d2a..a3dd6a2a755 100644 --- a/crates/rspack/tests/tree-shaking/var-function-expr/snapshot/new_treeshaking.snap +++ b/crates/rspack/tests/tree-shaking/var-function-expr/snapshot/new_treeshaking.snap @@ -15,7 +15,7 @@ __webpack_require__.d(__webpack_exports__, { _lib__WEBPACK_IMPORTED_MODULE_0_.result; }; var app2 = ()=>{ - _lib__WEBPACK_IMPORTED_MODULE_0_.secret; + secret; }; var app4 = (0, _lib__WEBPACK_IMPORTED_MODULE_0_.something)('app4'), app5 = 10000; var app3 = (0, _lib__WEBPACK_IMPORTED_MODULE_0_.something)('app3'); @@ -31,7 +31,6 @@ __webpack_require__.r(__webpack_exports__); 'use strict'; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { - 'secret': function() { return secret; }, 'result': function() { return result; }, 'something': function() { return something; } }); diff --git a/crates/rspack/tests/tree-shaking/var-function-expr/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/var-function-expr/snapshot/snap.diff index 07a1eb82343..360421900bc 100644 --- a/crates/rspack/tests/tree-shaking/var-function-expr/snapshot/snap.diff +++ b/crates/rspack/tests/tree-shaking/var-function-expr/snapshot/snap.diff @@ -5,15 +5,7 @@ }; var app2 = ()=>{ - /* "./lib" unused */null; -+ _lib__WEBPACK_IMPORTED_MODULE_0_.secret; ++ secret; }; var app4 = (0, _lib__WEBPACK_IMPORTED_MODULE_0_.something)('app4'), app5 = 10000; var app3 = (0, _lib__WEBPACK_IMPORTED_MODULE_0_.something)('app3'); -@@ -31,6 +31,7 @@ - 'use strict'; - __webpack_require__.r(__webpack_exports__); - __webpack_require__.d(__webpack_exports__, { -+ 'secret': function() { return secret; }, - 'result': function() { return result; }, - 'something': function() { return something; } - }); diff --git a/crates/rspack/tests/tree-shaking/webpack-innergraph-circular/snapshot/new_treeshaking.snap b/crates/rspack/tests/tree-shaking/webpack-innergraph-circular/snapshot/new_treeshaking.snap index 51d5ba52f34..5d34b7bb6b2 100644 --- a/crates/rspack/tests/tree-shaking/webpack-innergraph-circular/snapshot/new_treeshaking.snap +++ b/crates/rspack/tests/tree-shaking/webpack-innergraph-circular/snapshot/new_treeshaking.snap @@ -34,9 +34,6 @@ it("export should be unused when only unused functions use it", ()=>{ 'use strict'; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { - 'A': function() { return A; }, - 'B': function() { return B; }, - 'C': function() { return C; }, 'exportAUsed': function() { return exportAUsed; }, 'exportBUsed': function() { return exportBUsed; }, 'exportCUsed': function() { return exportCUsed; } @@ -77,15 +74,15 @@ function y(v) { } function withA(v) { const value = x(v); - return (0, _inner__WEBPACK_IMPORTED_MODULE_0_.A)(value); + return A(value); } function withB(v) { const value = x(v); - return (0, _inner__WEBPACK_IMPORTED_MODULE_0_.B)(value); + return B(value); } function withC(v) { const value = x(v); - return (0, _inner__WEBPACK_IMPORTED_MODULE_0_.C)(value); + return C(value); } }, diff --git a/crates/rspack/tests/tree-shaking/webpack-innergraph-circular/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/webpack-innergraph-circular/snapshot/snap.diff index 21e5a17af8b..8ed14cf5c09 100644 --- a/crates/rspack/tests/tree-shaking/webpack-innergraph-circular/snapshot/snap.diff +++ b/crates/rspack/tests/tree-shaking/webpack-innergraph-circular/snapshot/snap.diff @@ -1,14 +1,15 @@ --- expected +++ actual -@@ -36,6 +36,7 @@ +@@ -34,8 +34,6 @@ + 'use strict'; + __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { - 'A': function() { return A; }, - 'B': function() { return B; }, -+ 'C': function() { return C; }, +- 'A': function() { return A; }, +- 'B': function() { return B; }, 'exportAUsed': function() { return exportAUsed; }, 'exportBUsed': function() { return exportBUsed; }, 'exportCUsed': function() { return exportCUsed; } -@@ -49,8 +50,8 @@ +@@ -49,8 +47,8 @@ function C(s) { return s + "C"; } @@ -19,12 +20,22 @@ const exportCUsed = false; }, "./module.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -@@ -84,7 +85,7 @@ +@@ -76,15 +74,15 @@ + } + function withA(v) { + const value = x(v); +- return (0, _inner__WEBPACK_IMPORTED_MODULE_0_.A)(value); ++ return A(value); + } + function withB(v) { + const value = x(v); +- return (0, _inner__WEBPACK_IMPORTED_MODULE_0_.B)(value); ++ return B(value); } function withC(v) { const value = x(v); - return /* "./inner" unused */null(value); -+ return (0, _inner__WEBPACK_IMPORTED_MODULE_0_.C)(value); ++ return C(value); } }, diff --git a/crates/rspack/tests/tree-shaking/webpack-innergraph-no-side-effects/snapshot/new_treeshaking.snap b/crates/rspack/tests/tree-shaking/webpack-innergraph-no-side-effects/snapshot/new_treeshaking.snap index a205ad5ae0d..df98dc364d7 100644 --- a/crates/rspack/tests/tree-shaking/webpack-innergraph-no-side-effects/snapshot/new_treeshaking.snap +++ b/crates/rspack/tests/tree-shaking/webpack-innergraph-no-side-effects/snapshot/new_treeshaking.snap @@ -26,23 +26,14 @@ __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { 'a': function() { return a; } }); -/* harmony import */var _unusedModule__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./unusedModule */"./package/unusedModule.js"); function a() { return 42; } function b() { - return _unusedModule__WEBPACK_IMPORTED_MODULE_0_["default"]; + return value; } }, -"./package/unusedModule.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } -}); -var __WEBPACK_DEFAULT_EXPORT__ = 42; -}, },function(__webpack_require__) { var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } diff --git a/crates/rspack/tests/tree-shaking/webpack-innergraph-no-side-effects/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/webpack-innergraph-no-side-effects/snapshot/snap.diff index fdc2abc2f26..c37a3964dc2 100644 --- a/crates/rspack/tests/tree-shaking/webpack-innergraph-no-side-effects/snapshot/snap.diff +++ b/crates/rspack/tests/tree-shaking/webpack-innergraph-no-side-effects/snapshot/snap.diff @@ -1,27 +1,11 @@ --- expected +++ actual -@@ -26,14 +26,23 @@ - __webpack_require__.d(__webpack_exports__, { - 'a': function() { return a; } - }); -+/* harmony import */var _unusedModule__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./unusedModule */"./package/unusedModule.js"); - - function a() { +@@ -31,7 +31,7 @@ return 42; } function b() { - return /* "./unusedModule" unused */null; -+ return _unusedModule__WEBPACK_IMPORTED_MODULE_0_["default"]; ++ return value; } }, -+"./package/unusedModule.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -+'use strict'; -+__webpack_require__.r(__webpack_exports__); -+__webpack_require__.d(__webpack_exports__, { -+ 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } -+}); -+var __WEBPACK_DEFAULT_EXPORT__ = 42; -+}, - },function(__webpack_require__) { - var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } diff --git a/crates/rspack_binding_options/src/options/raw_optimization.rs b/crates/rspack_binding_options/src/options/raw_optimization.rs index f42496fb2d0..60d96bb5678 100644 --- a/crates/rspack_binding_options/src/options/raw_optimization.rs +++ b/crates/rspack_binding_options/src/options/raw_optimization.rs @@ -25,6 +25,7 @@ pub struct RawOptimizationOptions { pub side_effects: String, pub used_exports: String, pub provided_exports: bool, + pub inner_graph: bool, pub real_content_hash: bool, } @@ -75,6 +76,7 @@ impl RawOptionsApply for RawOptimizationOptions { side_effects: SideEffectOption::from(self.side_effects.as_str()), provided_exports: self.provided_exports, used_exports: UsedExportsOption::from(self.used_exports.as_str()), + inner_graph: self.inner_graph, }) } } diff --git a/crates/rspack_core/src/compiler/compilation.rs b/crates/rspack_core/src/compiler/compilation.rs index 482fa0c7cc1..90602ae8096 100644 --- a/crates/rspack_core/src/compiler/compilation.rs +++ b/crates/rspack_core/src/compiler/compilation.rs @@ -1187,14 +1187,7 @@ impl Compilation { // https://github.com/webpack/webpack/blob/d15c73469fd71cf98734685225250148b68ddc79/lib/Compilation.js#L2812-L2814 while plugin_driver.optimize_dependencies(self).await?.is_some() {} logger.time_end(start); - // if self.options.is_new_tree_shaking() { - // // for module in self.module_graph.module_graph_modules().values() {} - // // self - // // .module_graph - // // .module_graph_modules() - // // .values() - // // .foreach(|item| {}); // debug_exports_info(&self.module_graph); // } diff --git a/crates/rspack_core/src/context_module_factory.rs b/crates/rspack_core/src/context_module_factory.rs index d5798ecbc15..f7671cf7848 100644 --- a/crates/rspack_core/src/context_module_factory.rs +++ b/crates/rspack_core/src/context_module_factory.rs @@ -93,7 +93,7 @@ impl ContextModuleFactory { specifier, dependency_type: dependency.dependency_type(), dependency_category: dependency.category(), - span: dependency.span().cloned(), + span: dependency.span(), resolve_options: data.resolve_options.clone(), resolve_to_context: true, optional: false, diff --git a/crates/rspack_core/src/dependency/context_element_dependency.rs b/crates/rspack_core/src/dependency/context_element_dependency.rs index 45074be4ee7..49c1e1442ae 100644 --- a/crates/rspack_core/src/dependency/context_element_dependency.rs +++ b/crates/rspack_core/src/dependency/context_element_dependency.rs @@ -46,10 +46,6 @@ impl ModuleDependency for ContextElementDependency { &self.user_request } - fn span(&self) -> Option<&crate::ErrorSpan> { - None - } - fn weak(&self) -> bool { matches!( self.options.mode, diff --git a/crates/rspack_core/src/dependency/entry.rs b/crates/rspack_core/src/dependency/entry.rs index 81ea7345cb1..f35aa4bef3f 100644 --- a/crates/rspack_core/src/dependency/entry.rs +++ b/crates/rspack_core/src/dependency/entry.rs @@ -1,6 +1,6 @@ use crate::{ AsDependencyTemplate, Context, Dependency, DependencyCategory, DependencyId, DependencyType, - ErrorSpan, ModuleDependency, + ModuleDependency, }; #[derive(Debug, Hash, PartialEq, Eq, Clone)] @@ -47,10 +47,6 @@ impl ModuleDependency for EntryDependency { &self.request } - fn span(&self) -> Option<&ErrorSpan> { - None - } - fn set_request(&mut self, request: String) { self.request = request; } diff --git a/crates/rspack_core/src/dependency/mod.rs b/crates/rspack_core/src/dependency/mod.rs index eea740777c5..798dd1eab2d 100644 --- a/crates/rspack_core/src/dependency/mod.rs +++ b/crates/rspack_core/src/dependency/mod.rs @@ -16,7 +16,7 @@ pub use runtime_requirements_dependency::RuntimeRequirementsDependency; mod context_element_dependency; mod dependency_macro; pub use context_element_dependency::*; -use swc_core::ecma::atoms::JsWord; +use swc_core::{common::Span, ecma::atoms::JsWord}; mod const_dependency; use std::{ any::Any, @@ -32,7 +32,7 @@ use dyn_clone::{clone_trait_object, DynClone}; use crate::{ ChunkGroupOptionsKindRef, ConnectionState, Context, ContextMode, ContextOptions, ErrorSpan, ExtendedReferencedExport, ModuleGraph, ModuleGraphConnection, ModuleIdentifier, ReferencedExport, - RuntimeSpec, + RuntimeSpec, UsedByExports, }; // Used to describe dependencies' types, see webpack's `type` getter in `Dependency` @@ -191,6 +191,8 @@ pub trait Dependency: None } + fn set_used_by_exports(&mut self, _used_by_exports: Option) {} + fn get_module_evaluation_side_effects_state( &self, _module_graph: &ModuleGraph, @@ -198,6 +200,19 @@ pub trait Dependency: ) -> ConnectionState { ConnectionState::Bool(true) } + + fn span(&self) -> Option { + None + } + + fn is_span_equal(&self, other: &Span) -> bool { + if let Some(err_span) = self.span() { + let other = ErrorSpan::from(*other); + other == err_span + } else { + false + } + } } #[derive(Debug, Default)] @@ -355,7 +370,6 @@ pub trait ModuleDependency: Dependency { fn dependency_debug_name(&self) -> &'static str; fn request(&self) -> &str; fn user_request(&self) -> &str; - fn span(&self) -> Option<&ErrorSpan>; fn weak(&self) -> bool { false } diff --git a/crates/rspack_core/src/exports_info.rs b/crates/rspack_core/src/exports_info.rs index 3bb674d37b0..e9621e8a8fe 100644 --- a/crates/rspack_core/src/exports_info.rs +++ b/crates/rspack_core/src/exports_info.rs @@ -1109,21 +1109,19 @@ pub enum RuntimeUsageStateType { Used, } -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub enum UsedByExports { Set(HashSet), Bool(bool), - #[default] - Nil, } // https://github.com/webpack/webpack/blob/1f99ad6367f2b8a6ef17cce0e058f7a67fb7db18/lib/optimize/InnerGraph.js#L319-L338 pub fn get_dependency_used_by_exports_condition( dependency_id: DependencyId, - used_by_exports: &UsedByExports, + used_by_exports: Option<&UsedByExports>, ) -> Option { match used_by_exports { - UsedByExports::Set(used_by_exports) => { + Some(UsedByExports::Set(used_by_exports)) => { let used_by_exports = Arc::new(used_by_exports.clone()); Some(DependencyCondition::Fn(Box::new( move |_, runtime, module_graph: &ModuleGraph| { @@ -1142,14 +1140,14 @@ pub fn get_dependency_used_by_exports_condition( }, ))) } - UsedByExports::Bool(bool) => { + Some(UsedByExports::Bool(bool)) => { if *bool { None } else { Some(DependencyCondition::False) } } - UsedByExports::Nil => None, + None => None, } } diff --git a/crates/rspack_core/src/module_graph/connection.rs b/crates/rspack_core/src/module_graph/connection.rs index 7009a3110c1..11f507a68f4 100644 --- a/crates/rspack_core/src/module_graph/connection.rs +++ b/crates/rspack_core/src/module_graph/connection.rs @@ -108,6 +108,7 @@ impl ModuleGraphConnection { if !self.conditional { return ConnectionState::Bool(self.active); } + self.get_condition_state(module_graph, runtime) } diff --git a/crates/rspack_core/src/module_graph/mod.rs b/crates/rspack_core/src/module_graph/mod.rs index eec01d18c41..8eeee31fbef 100644 --- a/crates/rspack_core/src/module_graph/mod.rs +++ b/crates/rspack_core/src/module_graph/mod.rs @@ -681,10 +681,6 @@ mod test { &*self.1 } - fn span(&self) -> Option<&crate::ErrorSpan> { - unreachable!() - } - fn set_request(&mut self, request: String) { self.1 = request; } diff --git a/crates/rspack_core/src/normal_module_factory.rs b/crates/rspack_core/src/normal_module_factory.rs index 95325711df8..8062ed4df86 100644 --- a/crates/rspack_core/src/normal_module_factory.rs +++ b/crates/rspack_core/src/normal_module_factory.rs @@ -305,7 +305,7 @@ impl NormalModuleFactory { specifier: request_without_match_resource, dependency_type: dependency.dependency_type(), dependency_category: dependency.category(), - span: dependency.span().cloned(), + span: dependency.span(), // take the options is safe here, because it // is not used in after_resolve hooks resolve_options: data.resolve_options.take(), @@ -380,7 +380,7 @@ impl NormalModuleFactory { dependency_type: dependency.dependency_type(), dependency_category: dependency.category(), resolve_options: data.resolve_options.take(), - span: dependency.span().cloned(), + span: dependency.span(), resolve_to_context: false, optional, missing_dependencies: &mut missing_dependencies, diff --git a/crates/rspack_core/src/options/optimizations.rs b/crates/rspack_core/src/options/optimizations.rs index c42793a78f7..4fe2f346687 100644 --- a/crates/rspack_core/src/options/optimizations.rs +++ b/crates/rspack_core/src/options/optimizations.rs @@ -99,4 +99,5 @@ pub struct Optimization { pub side_effects: SideEffectOption, pub provided_exports: bool, pub used_exports: UsedExportsOption, + pub inner_graph: bool, } diff --git a/crates/rspack_loader_sass/tests/fixtures.rs b/crates/rspack_loader_sass/tests/fixtures.rs index 76cff787f7e..1e5f50b8eea 100644 --- a/crates/rspack_loader_sass/tests/fixtures.rs +++ b/crates/rspack_loader_sass/tests/fixtures.rs @@ -90,6 +90,7 @@ async fn loader_test(actual: impl AsRef, expected: impl AsRef) { side_effects: SideEffectOption::False, provided_exports: Default::default(), used_exports: Default::default(), + inner_graph: Default::default(), }, profile: false, }), diff --git a/crates/rspack_loader_swc/tests/fixtures.rs b/crates/rspack_loader_swc/tests/fixtures.rs index 5140f574d5f..98b29b9b9c3 100644 --- a/crates/rspack_loader_swc/tests/fixtures.rs +++ b/crates/rspack_loader_swc/tests/fixtures.rs @@ -90,6 +90,7 @@ async fn loader_test(actual: impl AsRef, expected: impl AsRef) { side_effects: SideEffectOption::False, provided_exports: Default::default(), used_exports: Default::default(), + inner_graph: Default::default(), }, profile: false, }), diff --git a/crates/rspack_plugin_css/src/dependency/compose.rs b/crates/rspack_plugin_css/src/dependency/compose.rs index ce6c0c5c9e6..2afb085c4b6 100644 --- a/crates/rspack_plugin_css/src/dependency/compose.rs +++ b/crates/rspack_plugin_css/src/dependency/compose.rs @@ -32,6 +32,10 @@ impl Dependency for CssComposeDependency { fn dependency_type(&self) -> &DependencyType { &DependencyType::CssCompose } + + fn span(&self) -> Option { + self.span + } } impl ModuleDependency for CssComposeDependency { @@ -43,10 +47,6 @@ impl ModuleDependency for CssComposeDependency { &self.request } - fn span(&self) -> Option<&ErrorSpan> { - self.span.as_ref() - } - fn set_request(&mut self, request: String) { self.request = request; } diff --git a/crates/rspack_plugin_css/src/dependency/import.rs b/crates/rspack_plugin_css/src/dependency/import.rs index 35463bdff55..9559e872e31 100644 --- a/crates/rspack_plugin_css/src/dependency/import.rs +++ b/crates/rspack_plugin_css/src/dependency/import.rs @@ -36,6 +36,10 @@ impl Dependency for CssImportDependency { fn dependency_type(&self) -> &DependencyType { &DependencyType::CssImport } + + fn span(&self) -> Option { + self.span + } } impl ModuleDependency for CssImportDependency { @@ -47,10 +51,6 @@ impl ModuleDependency for CssImportDependency { &self.request } - fn span(&self) -> Option<&ErrorSpan> { - self.span.as_ref() - } - fn set_request(&mut self, request: String) { self.request = request; } diff --git a/crates/rspack_plugin_css/src/dependency/url.rs b/crates/rspack_plugin_css/src/dependency/url.rs index b143ae26167..8ea67c41c38 100644 --- a/crates/rspack_plugin_css/src/dependency/url.rs +++ b/crates/rspack_plugin_css/src/dependency/url.rs @@ -66,6 +66,10 @@ impl Dependency for CssUrlDependency { fn dependency_type(&self) -> &DependencyType { &DependencyType::CssUrl } + + fn span(&self) -> Option { + self.span + } } impl ModuleDependency for CssUrlDependency { @@ -77,10 +81,6 @@ impl ModuleDependency for CssUrlDependency { &self.request } - fn span(&self) -> Option<&ErrorSpan> { - self.span.as_ref() - } - fn set_request(&mut self, request: String) { self.request = request; } diff --git a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_require_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_require_dependency.rs index 4313771b6df..05a8b7f55a0 100644 --- a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_require_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_require_dependency.rs @@ -46,6 +46,10 @@ impl Dependency for CommonJsRequireDependency { fn dependency_type(&self) -> &DependencyType { &DependencyType::CjsRequire } + + fn span(&self) -> Option { + self.span + } } impl ModuleDependency for CommonJsRequireDependency { @@ -57,10 +61,6 @@ impl ModuleDependency for CommonJsRequireDependency { &self.request } - fn span(&self) -> Option<&ErrorSpan> { - self.span.as_ref() - } - fn get_optional(&self) -> bool { self.optional } diff --git a/crates/rspack_plugin_javascript/src/dependency/commonjs/require_resolve_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/commonjs/require_resolve_dependency.rs index 60b56d9fc55..29ae1b7876a 100644 --- a/crates/rspack_plugin_javascript/src/dependency/commonjs/require_resolve_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/commonjs/require_resolve_dependency.rs @@ -48,6 +48,10 @@ impl Dependency for RequireResolveDependency { fn dependency_type(&self) -> &DependencyType { &DependencyType::RequireResolve } + + fn span(&self) -> Option { + Some(self.span) + } } impl ModuleDependency for RequireResolveDependency { @@ -59,10 +63,6 @@ impl ModuleDependency for RequireResolveDependency { &self.request } - fn span(&self) -> Option<&ErrorSpan> { - Some(&self.span) - } - fn weak(&self) -> bool { self.weak } diff --git a/crates/rspack_plugin_javascript/src/dependency/context/common_js_require_context_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/context/common_js_require_context_dependency.rs index c9723ffe0a4..d8e7191ddac 100644 --- a/crates/rspack_plugin_javascript/src/dependency/context/common_js_require_context_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/context/common_js_require_context_dependency.rs @@ -48,6 +48,10 @@ impl Dependency for CommonJsRequireContextDependency { fn dependency_type(&self) -> &DependencyType { &DependencyType::CommonJSRequireContext } + + fn span(&self) -> Option { + self.span + } } impl ModuleDependency for CommonJsRequireContextDependency { @@ -59,10 +63,6 @@ impl ModuleDependency for CommonJsRequireContextDependency { &self.options.request } - fn span(&self) -> Option<&ErrorSpan> { - self.span.as_ref() - } - fn options(&self) -> Option<&ContextOptions> { Some(&self.options) } diff --git a/crates/rspack_plugin_javascript/src/dependency/context/import_context_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/context/import_context_dependency.rs index a2f74d2df0f..a5dc29ce48b 100644 --- a/crates/rspack_plugin_javascript/src/dependency/context/import_context_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/context/import_context_dependency.rs @@ -48,6 +48,10 @@ impl Dependency for ImportContextDependency { fn dependency_type(&self) -> &DependencyType { &DependencyType::ImportContext } + + fn span(&self) -> Option { + self.span + } } impl ModuleDependency for ImportContextDependency { @@ -59,10 +63,6 @@ impl ModuleDependency for ImportContextDependency { &self.options.request } - fn span(&self) -> Option<&ErrorSpan> { - self.span.as_ref() - } - fn options(&self) -> Option<&ContextOptions> { Some(&self.options) } diff --git a/crates/rspack_plugin_javascript/src/dependency/context/require_context_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/context/require_context_dependency.rs index 94d8e95b479..f56486bf3f3 100644 --- a/crates/rspack_plugin_javascript/src/dependency/context/require_context_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/context/require_context_dependency.rs @@ -40,6 +40,10 @@ impl Dependency for RequireContextDependency { fn dependency_type(&self) -> &DependencyType { &DependencyType::RequireContext } + + fn span(&self) -> Option { + self.span + } } impl ModuleDependency for RequireContextDependency { @@ -51,10 +55,6 @@ impl ModuleDependency for RequireContextDependency { &self.options.request } - fn span(&self) -> Option<&ErrorSpan> { - self.span.as_ref() - } - fn options(&self) -> Option<&ContextOptions> { Some(&self.options) } diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_imported_specifier_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_imported_specifier_dependency.rs index f5c71bbd48a..9485ab96f3a 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_imported_specifier_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_imported_specifier_dependency.rs @@ -1,7 +1,7 @@ use rspack_core::{ create_exports_object_referenced, create_no_exports_referenced, export_from_import, get_exports_type, process_export_info, ConnectionState, Dependency, DependencyCategory, - DependencyCondition, DependencyId, DependencyTemplate, DependencyType, ErrorSpan, ExportInfoId, + DependencyCondition, DependencyId, DependencyTemplate, DependencyType, ExportInfoId, ExportInfoProvided, ExportsType, ExtendedReferencedExport, HarmonyExportInitFragment, ModuleDependency, ModuleGraph, ModuleIdentifier, RuntimeSpec, TemplateContext, TemplateReplaceSource, UsageState, UsedName, @@ -510,10 +510,6 @@ impl ModuleDependency for HarmonyExportImportedSpecifierDependency { &self.request } - fn span(&self) -> Option<&ErrorSpan> { - None - } - fn set_request(&mut self, request: String) { self.request = request.into(); } diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_dependency.rs index 41f13bf738f..8407c7cc138 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_dependency.rs @@ -233,6 +233,10 @@ impl Dependency for HarmonyImportSideEffectDependency { &self.id } + fn span(&self) -> Option { + self.span + } + fn category(&self) -> &DependencyCategory { &DependencyCategory::Esm } @@ -270,10 +274,6 @@ impl ModuleDependency for HarmonyImportSideEffectDependency { &self.request } - fn span(&self) -> Option<&ErrorSpan> { - self.span.as_ref() - } - fn set_request(&mut self, request: String) { self.request = request.into(); } diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_specifier_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_specifier_dependency.rs index 465751d4dca..a48f5bb856e 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_specifier_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_specifier_dependency.rs @@ -3,9 +3,9 @@ use rspack_core::{ get_dependency_used_by_exports_condition, get_exports_type, tree_shaking::symbol::DEFAULT_JS_WORD, Compilation, ConnectionState, Dependency, DependencyCategory, DependencyCondition, DependencyId, DependencyTemplate, DependencyType, - ErrorSpan, ExportsType, ExtendedReferencedExport, ModuleDependency, ModuleGraph, - ModuleGraphModule, ModuleIdentifier, ReferencedExport, RuntimeSpec, TemplateContext, - TemplateReplaceSource, UsedByExports, + ExportsType, ExtendedReferencedExport, ModuleDependency, ModuleGraph, ModuleGraphModule, + ModuleIdentifier, ReferencedExport, RuntimeSpec, TemplateContext, TemplateReplaceSource, + UsedByExports, }; use rustc_hash::FxHashSet as HashSet; use swc_core::ecma::atoms::JsWord; @@ -26,7 +26,7 @@ pub struct HarmonyImportSpecifierDependency { call: bool, direct_import: bool, specifier: Specifier, - used_by_exports: UsedByExports, + used_by_exports: Option, namespace_object_as_context: bool, referenced_properties_in_destructuring: Option>, resource_identifier: String, @@ -58,7 +58,7 @@ impl HarmonyImportSpecifierDependency { call, direct_import, specifier, - used_by_exports: UsedByExports::default(), + used_by_exports: None, namespace_object_as_context: false, referenced_properties_in_destructuring, resource_identifier, @@ -197,7 +197,15 @@ impl Dependency for HarmonyImportSpecifierDependency { fn id(&self) -> &DependencyId { &self.id } - + fn span(&self) -> Option { + Some(rspack_core::ErrorSpan { + start: self.start, + end: self.end, + }) + } + fn set_used_by_exports(&mut self, used_by_exports: Option) { + self.used_by_exports = used_by_exports; + } fn category(&self) -> &DependencyCategory { &DependencyCategory::Esm } @@ -224,10 +232,6 @@ impl ModuleDependency for HarmonyImportSpecifierDependency { &self.request } - fn span(&self) -> Option<&ErrorSpan> { - None - } - fn set_request(&mut self, request: String) { self.request = request.into(); } @@ -237,7 +241,13 @@ impl ModuleDependency for HarmonyImportSpecifierDependency { } fn get_condition(&self) -> Option { - get_dependency_used_by_exports_condition(self.id, &self.used_by_exports) + // dbg!( + // &self.ids, + // &self.specifier, + // self.request(), + // self.used_by_exports.as_ref() + // ); + get_dependency_used_by_exports_condition(self.id, self.used_by_exports.as_ref()) } fn get_referenced_exports( @@ -245,6 +255,7 @@ impl ModuleDependency for HarmonyImportSpecifierDependency { module_graph: &ModuleGraph, _runtime: Option<&RuntimeSpec>, ) -> Vec { + // TODO: use self.getIds() instead // namespace import if self.ids.is_empty() { return self.get_referenced_exports_in_destructuring(None); diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/import_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/import_dependency.rs index 271e3353410..94b317e70d2 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/import_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/import_dependency.rs @@ -52,6 +52,10 @@ impl Dependency for ImportDependency { fn dependency_type(&self) -> &DependencyType { &DependencyType::DynamicImport } + + fn span(&self) -> Option { + self.span + } } impl ModuleDependency for ImportDependency { @@ -63,10 +67,6 @@ impl ModuleDependency for ImportDependency { &self.request } - fn span(&self) -> Option<&ErrorSpan> { - self.span.as_ref() - } - fn group_options(&self) -> Option { Some(ChunkGroupOptionsKindRef::Normal(&self.group_options)) } diff --git a/crates/rspack_plugin_javascript/src/dependency/hmr/import_meta_hot_accept.rs b/crates/rspack_plugin_javascript/src/dependency/hmr/import_meta_hot_accept.rs index 75564c994c5..78aa833f455 100644 --- a/crates/rspack_plugin_javascript/src/dependency/hmr/import_meta_hot_accept.rs +++ b/crates/rspack_plugin_javascript/src/dependency/hmr/import_meta_hot_accept.rs @@ -37,6 +37,10 @@ impl Dependency for ImportMetaHotAcceptDependency { fn dependency_type(&self) -> &DependencyType { &DependencyType::ImportMetaHotAccept } + + fn span(&self) -> Option { + self.span + } } impl ModuleDependency for ImportMetaHotAcceptDependency { @@ -48,10 +52,6 @@ impl ModuleDependency for ImportMetaHotAcceptDependency { &self.request } - fn span(&self) -> Option<&ErrorSpan> { - self.span.as_ref() - } - fn set_request(&mut self, request: String) { self.request = request.into(); } diff --git a/crates/rspack_plugin_javascript/src/dependency/hmr/import_meta_hot_decline.rs b/crates/rspack_plugin_javascript/src/dependency/hmr/import_meta_hot_decline.rs index 246e5e42aaa..c1701fa7b92 100644 --- a/crates/rspack_plugin_javascript/src/dependency/hmr/import_meta_hot_decline.rs +++ b/crates/rspack_plugin_javascript/src/dependency/hmr/import_meta_hot_decline.rs @@ -37,6 +37,10 @@ impl Dependency for ImportMetaHotDeclineDependency { fn dependency_type(&self) -> &DependencyType { &DependencyType::ImportMetaHotDecline } + + fn span(&self) -> Option { + self.span + } } impl ModuleDependency for ImportMetaHotDeclineDependency { @@ -48,10 +52,6 @@ impl ModuleDependency for ImportMetaHotDeclineDependency { &self.request } - fn span(&self) -> Option<&ErrorSpan> { - self.span.as_ref() - } - fn set_request(&mut self, request: String) { self.request = request.into(); } diff --git a/crates/rspack_plugin_javascript/src/dependency/hmr/module_hot_accept.rs b/crates/rspack_plugin_javascript/src/dependency/hmr/module_hot_accept.rs index cf1d1361857..18fc20556d3 100644 --- a/crates/rspack_plugin_javascript/src/dependency/hmr/module_hot_accept.rs +++ b/crates/rspack_plugin_javascript/src/dependency/hmr/module_hot_accept.rs @@ -37,6 +37,10 @@ impl Dependency for ModuleHotAcceptDependency { fn dependency_type(&self) -> &DependencyType { &DependencyType::ModuleHotAccept } + + fn span(&self) -> Option { + self.span + } } impl ModuleDependency for ModuleHotAcceptDependency { @@ -48,10 +52,6 @@ impl ModuleDependency for ModuleHotAcceptDependency { &self.request } - fn span(&self) -> Option<&ErrorSpan> { - self.span.as_ref() - } - fn set_request(&mut self, request: String) { self.request = request.into(); } diff --git a/crates/rspack_plugin_javascript/src/dependency/hmr/module_hot_decline.rs b/crates/rspack_plugin_javascript/src/dependency/hmr/module_hot_decline.rs index 86b2bb3457e..6c2741fd9b4 100644 --- a/crates/rspack_plugin_javascript/src/dependency/hmr/module_hot_decline.rs +++ b/crates/rspack_plugin_javascript/src/dependency/hmr/module_hot_decline.rs @@ -37,6 +37,10 @@ impl Dependency for ModuleHotDeclineDependency { fn dependency_type(&self) -> &DependencyType { &DependencyType::ModuleHotDecline } + + fn span(&self) -> Option { + self.span + } } impl ModuleDependency for ModuleHotDeclineDependency { @@ -48,10 +52,6 @@ impl ModuleDependency for ModuleHotDeclineDependency { &self.request } - fn span(&self) -> Option<&ErrorSpan> { - self.span.as_ref() - } - fn set_request(&mut self, request: String) { self.request = request.into(); } diff --git a/crates/rspack_plugin_javascript/src/dependency/mod.rs b/crates/rspack_plugin_javascript/src/dependency/mod.rs index 432a5b91781..ee87cf89f25 100644 --- a/crates/rspack_plugin_javascript/src/dependency/mod.rs +++ b/crates/rspack_plugin_javascript/src/dependency/mod.rs @@ -4,6 +4,7 @@ mod esm; mod export_info_api_dep; mod hmr; mod module_argument_dependency; +mod pure_expression_dependency; mod url; mod worker; pub use commonjs::*; @@ -12,6 +13,7 @@ pub use esm::*; pub use export_info_api_dep::*; pub use hmr::*; pub use module_argument_dependency::*; +pub use pure_expression_dependency::*; pub use worker::*; pub use self::url::*; diff --git a/crates/rspack_plugin_javascript/src/dependency/pure_expression_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/pure_expression_dependency.rs new file mode 100644 index 00000000000..5ab4547c976 --- /dev/null +++ b/crates/rspack_plugin_javascript/src/dependency/pure_expression_dependency.rs @@ -0,0 +1,51 @@ +use rspack_core::{ + AsModuleDependency, Dependency, DependencyId, DependencyTemplate, TemplateContext, + TemplateReplaceSource, UsedByExports, +}; +#[derive(Debug, Clone)] +pub struct PureExpressionDependency { + pub start: u32, + pub end: u32, + pub used_by_exports: Option, + id: DependencyId, +} + +impl PureExpressionDependency { + pub fn new(start: u32, end: u32) -> Self { + Self { + start, + end, + used_by_exports: None, + id: DependencyId::default(), + } + } +} + +impl Dependency for PureExpressionDependency { + fn id(&self) -> &rspack_core::DependencyId { + &self.id + } + + fn set_used_by_exports(&mut self, used_by_exports: Option) { + self.used_by_exports = used_by_exports; + } +} + +impl AsModuleDependency for PureExpressionDependency { + fn as_module_dependency(&self) -> Option<&dyn rspack_core::ModuleDependency> { + None + } + + fn as_module_dependency_mut(&mut self) -> Option<&mut dyn rspack_core::ModuleDependency> { + None + } +} + +impl DependencyTemplate for PureExpressionDependency { + fn apply( + &self, + _source: &mut TemplateReplaceSource, + _code_generatable_context: &mut TemplateContext, + ) { + } +} diff --git a/crates/rspack_plugin_javascript/src/dependency/url/mod.rs b/crates/rspack_plugin_javascript/src/dependency/url/mod.rs index 0d03441f81b..3a4ce5e3073 100644 --- a/crates/rspack_plugin_javascript/src/dependency/url/mod.rs +++ b/crates/rspack_plugin_javascript/src/dependency/url/mod.rs @@ -12,7 +12,7 @@ pub struct URLDependency { id: DependencyId, request: JsWord, span: Option, - used_by_exports: UsedByExports, + used_by_exports: Option, } impl URLDependency { @@ -23,7 +23,7 @@ impl URLDependency { id: DependencyId::new(), request, span, - used_by_exports: UsedByExports::default(), + used_by_exports: None, } } } @@ -40,6 +40,10 @@ impl Dependency for URLDependency { fn dependency_type(&self) -> &DependencyType { &DependencyType::NewUrl } + + fn span(&self) -> Option { + self.span + } } impl ModuleDependency for URLDependency { @@ -51,16 +55,12 @@ impl ModuleDependency for URLDependency { &self.request } - fn span(&self) -> Option<&ErrorSpan> { - self.span.as_ref() - } - fn set_request(&mut self, request: String) { self.request = request.into(); } fn get_condition(&self) -> Option { - get_dependency_used_by_exports_condition(self.id, &self.used_by_exports) + get_dependency_used_by_exports_condition(self.id, self.used_by_exports.as_ref()) } fn dependency_debug_name(&self) -> &'static str { diff --git a/crates/rspack_plugin_javascript/src/dependency/worker/mod.rs b/crates/rspack_plugin_javascript/src/dependency/worker/mod.rs index 0491ffade6d..60a06371dd6 100644 --- a/crates/rspack_plugin_javascript/src/dependency/worker/mod.rs +++ b/crates/rspack_plugin_javascript/src/dependency/worker/mod.rs @@ -48,6 +48,10 @@ impl Dependency for WorkerDependency { fn dependency_type(&self) -> &DependencyType { &DependencyType::NewWorker } + + fn span(&self) -> Option { + self.span + } } impl ModuleDependency for WorkerDependency { @@ -59,10 +63,6 @@ impl ModuleDependency for WorkerDependency { &self.request } - fn span(&self) -> Option<&ErrorSpan> { - self.span.as_ref() - } - fn set_request(&mut self, request: String) { self.request = request; } diff --git a/crates/rspack_plugin_javascript/src/parser_and_generator/mod.rs b/crates/rspack_plugin_javascript/src/parser_and_generator/mod.rs index b57aa25e570..6318883b06e 100644 --- a/crates/rspack_plugin_javascript/src/parser_and_generator/mod.rs +++ b/crates/rspack_plugin_javascript/src/parser_and_generator/mod.rs @@ -12,7 +12,9 @@ use rspack_core::{ use rspack_error::{internal_error, IntoTWithDiagnosticArray, Result, TWithDiagnosticArray}; use swc_core::common::SyntaxContext; +use crate::inner_graph_plugin::InnerGraphPlugin; use crate::utils::syntax_by_module_type; +use crate::visitors::ScanDependenciesResult; use crate::visitors::{run_before_pass, scan_dependencies, swc_visitor::resolver}; use crate::{SideEffectsFlagPluginVisitor, SyntaxContextInfo}; #[derive(Debug)] @@ -127,7 +129,12 @@ impl ParserAndGenerator for JavaScriptParserAndGenerator { )); }); - let (dependencies, presentational_dependencies) = ast.visit(|program, context| { + let ScanDependenciesResult { + mut dependencies, + presentational_dependencies, + mut rewrite_usage_span, + import_map, + } = ast.visit(|program, context| { scan_dependencies( program, context.unresolved_mark, @@ -158,6 +165,26 @@ impl ParserAndGenerator for JavaScriptParserAndGenerator { }); } + let inner_graph = + if compiler_options.is_new_tree_shaking() && compiler_options.optimization.inner_graph { + ast.transform(|program, context| { + let unresolved_ctxt = SyntaxContext::empty().apply_mark(context.unresolved_mark); + let top_level_ctxt = SyntaxContext::empty().apply_mark(context.top_level_mark); + let mut plugin = InnerGraphPlugin::new( + &mut dependencies, + unresolved_ctxt, + top_level_ctxt, + &mut rewrite_usage_span, + &import_map, + ); + plugin.enable(); + program.visit_with(&mut plugin); + Some(plugin) + }) + } else { + None + }; + let source = if let Some(map) = output.map { SourceMapSource::new(SourceMapSourceOptions { value: output.code, @@ -180,6 +207,9 @@ impl ParserAndGenerator for JavaScriptParserAndGenerator { } RawSource::from(content).boxed() } + if let Some(mut inner_graph) = inner_graph { + inner_graph.infer_dependency_usage(); + } Ok( ParseResult { diff --git a/crates/rspack_plugin_javascript/src/plugin/inner_graph_plugin.rs b/crates/rspack_plugin_javascript/src/plugin/inner_graph_plugin.rs new file mode 100644 index 00000000000..55a91daff35 --- /dev/null +++ b/crates/rspack_plugin_javascript/src/plugin/inner_graph_plugin.rs @@ -0,0 +1,617 @@ +use std::{collections::hash_map::Entry, hash::Hash}; + +use rspack_core::{Dependency, SpanExt, UsedByExports}; +use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet}; +use swc_core::{ + common::{Span, Spanned, SyntaxContext}, + ecma::{ + ast::{ + ArrowExpr, CallExpr, Callee, Class, ClassDecl, ClassMember, DefaultDecl, ExportDecl, + ExportDefaultDecl, ExportDefaultExpr, ExportSpecifier, Expr, FnDecl, FnExpr, Ident, + MemberExpr, NamedExport, Pat, Program, Prop, VarDeclarator, + }, + atoms::JsWord, + visit::{noop_visit_type, Visit, VisitWith}, + }, +}; + +use crate::{ + dependency::{PureExpressionDependency, DEFAULT_EXPORT}, + plugin::side_effects_flag_plugin::{is_pure_class, is_pure_expression}, + visitors::{harmony_import_dependency_scanner::ImportMap, ExtraSpanInfo}, + ClassKey, +}; + +#[derive(Hash, PartialEq, Eq, Clone, Debug)] +pub enum InnerGraphMapSetValue { + TopLevel(JsWord), + Str(JsWord), +} + +/// You need to make sure that InnerGraphMapUsage is not a [InnerGraphMapUsage::True] variant +impl From for InnerGraphMapSetValue { + fn from(value: InnerGraphMapUsage) -> Self { + match value { + InnerGraphMapUsage::TopLevel(str) => Self::TopLevel(str), + InnerGraphMapUsage::Value(str) => Self::Str(str), + InnerGraphMapUsage::True => unreachable!(""), + } + } +} + +impl InnerGraphMapSetValue { + fn to_jsword(&self) -> &JsWord { + match self { + InnerGraphMapSetValue::TopLevel(v) => v, + InnerGraphMapSetValue::Str(v) => v, + } + } +} + +#[derive(Default, Clone, PartialEq, Eq, Debug)] +pub enum InnerGraphMapValue { + Set(HashSet), + True, + #[default] + Nil, +} + +#[derive(PartialEq, Eq, Debug)] +pub enum InnerGraphMapUsage { + TopLevel(JsWord), + Value(JsWord), + True, +} + +pub type UsageCallback = Box>, Option)>; + +#[derive(Default)] +pub struct InnerGraphState { + inner_graph: HashMap, + usage_callback_map: HashMap>, + current_top_level_symbol: Option, + enable: bool, +} + +pub struct InnerGraphPlugin<'a> { + dependencies: &'a mut Vec>, + unresolved_ctxt: SyntaxContext, + top_level_ctxt: SyntaxContext, + state: InnerGraphState, + scope_level: usize, + rewrite_usage_span: &'a mut HashMap, + import_map: &'a ImportMap, +} + +impl<'a> Visit for InnerGraphPlugin<'a> { + noop_visit_type!(); + fn visit_program(&mut self, program: &Program) { + if !self.is_enabled() { + return; + } + program.visit_children_with(self); + } + + fn visit_call_expr(&mut self, call_expr: &CallExpr) { + // https://github.com/webpack/webpack/blob/main/lib/JavascriptMetaInfoPlugin.js#L46 + if let Callee::Expr(box Expr::Ident(ident)) = &call_expr.callee && &ident.sym == "eval" { + if let Some(current_symbol) = self.get_top_level_symbol() { + // We use `""` to represent `null + self.add_usage("".into(), InnerGraphMapUsage::TopLevel(current_symbol)); + } else { + self.bailout(); + return; + } + } + call_expr.visit_children_with(self); + } + + fn visit_member_expr(&mut self, member_expr: &MemberExpr) { + if let Some(ExtraSpanInfo::ReWriteUsedByExports) = + self.rewrite_usage_span.get(&member_expr.span) + { + let span = member_expr.span; + self.on_usage(Box::new(move |deps, used_by_exports| { + let target_dep = deps.iter_mut().find(|item| item.is_span_equal(&span)); + if let Some(dep) = target_dep { + dep.set_used_by_exports(used_by_exports); + } + })); + }; + } + + fn visit_class_member(&mut self, node: &ClassMember) { + if let Some(key) = node.class_key() && key.is_computed() { + key.visit_with(self); + } + + let increase_level = match node { + ClassMember::Constructor(_) => 1, + ClassMember::Method(_) => 1, + ClassMember::PrivateMethod(_) => 1, + ClassMember::ClassProp(_) => 0, + ClassMember::PrivateProp(_) => 0, + ClassMember::TsIndexSignature(_) => unreachable!(), + ClassMember::Empty(_) => 0, + ClassMember::StaticBlock(_) => 1, + ClassMember::AutoAccessor(_) => 0, + }; + let scope_level = self.scope_level; + self.scope_level += increase_level; + node.visit_children_with(self); + self.scope_level = scope_level; + } + + fn visit_fn_decl(&mut self, node: &FnDecl) { + self.set_symbol_if_is_top_level(node.ident.sym.clone()); + let scope_level = self.scope_level; + self.scope_level += 1; + node.function.visit_children_with(self); + self.scope_level = scope_level; + self.clear_symbol_if_is_top_level(); + } + + // TODO: expr + fn visit_fn_expr(&mut self, node: &FnExpr) { + let scope_level = self.scope_level; + self.scope_level += 1; + node.visit_children_with(self); + self.scope_level = scope_level; + } + + fn visit_arrow_expr(&mut self, node: &ArrowExpr) { + let scope_level = self.scope_level; + self.scope_level += 1; + node.visit_children_with(self); + self.scope_level = scope_level; + } + + fn visit_class_decl(&mut self, node: &ClassDecl) { + if !self.is_enabled() { + return; + } + + let scope_level = self.scope_level; + self.scope_level += 1; + // TODO: consider class + node.visit_children_with(self); + self.scope_level = scope_level; + } + + fn visit_ident(&mut self, ident: &Ident) { + if let Some(ExtraSpanInfo::ReWriteUsedByExports) = self.rewrite_usage_span.get(&ident.span) { + let span = ident.span; + self.on_usage(Box::new(move |deps, used_by_exports| { + let target_dep = deps.iter_mut().find(|item| item.is_span_equal(&span)); + if let Some(dep) = target_dep { + dep.set_used_by_exports(used_by_exports); + } + })); + }; + // imported binding isn't considered as a top level symbol. + if self.import_map.contains_key(&ident.to_id()) { + return; + }; + if ident.span.ctxt == self.top_level_ctxt { + let usage = if let Some(symbol) = self.get_top_level_symbol() { + InnerGraphMapUsage::TopLevel(symbol) + } else { + InnerGraphMapUsage::True + }; + self.add_usage(ident.sym.clone(), usage); + } + } + + fn visit_var_declarator(&mut self, n: &VarDeclarator) { + if !self.is_enabled() { + return; + } + + if let Pat::Ident(ident) = &n.name && let Some(box init) = &n.init && is_pure_expression(init, self.unresolved_ctxt) { + let symbol = ident.id.sym.clone(); + match init { + Expr::Fn(_) | Expr::Arrow(_) | Expr::Lit(_) => { + self.set_symbol_if_is_top_level(symbol); + init.visit_children_with(self); + self.clear_symbol_if_is_top_level(); + }, + Expr::Class(class) => { + // TODO: consider class + class.class.visit_children_with(self); + } + _ => { + init.visit_children_with(self); + if self.has_toplevel_symbol() && is_pure_expression(init, self.unresolved_ctxt) { + let start = init.span().real_lo(); + let end = init.span().real_hi(); + self.on_usage(Box::new(move |deps, used_by_exports| { + match used_by_exports { + Some(UsedByExports::Bool(true)) | None=> {}, + _ => { + let mut dep = PureExpressionDependency::new(start, end); + dep.used_by_exports = used_by_exports; + deps.push(Box::new(dep)); + } + } + })); + } + } + } + } else { + n.init.visit_with(self); + } + } + + fn visit_prop(&mut self, n: &Prop) { + match n { + Prop::Shorthand(shorthand) => { + if let Some(ExtraSpanInfo::ReWriteUsedByExports) = + self.rewrite_usage_span.get(&shorthand.span) + { + let span = shorthand.span; + self.on_usage(Box::new(move |deps, used_by_exports| { + let target_dep = deps.iter_mut().find(|item| item.is_span_equal(&span)); + if let Some(dep) = target_dep { + dep.set_used_by_exports(used_by_exports); + } + })); + }; + } + _ => n.visit_children_with(self), + } + } + fn visit_export_decl(&mut self, export_decl: &ExportDecl) { + if let Some(ExtraSpanInfo::AddVariableUsage(sym, usage)) = + self.rewrite_usage_span.get(&export_decl.span) + { + self.add_variable_usage(sym.clone(), InnerGraphMapUsage::Value(usage.clone())); + } + // match &export_decl.decl { + // Decl::Class(ClassDecl { ident, .. }) | Decl::Fn(FnDecl { ident, .. }) => { + // // self.add_variable_usage(ident.sym.clone(), ident.sym.clone()); + // } + // Decl::Var(v) => { + // find_pat_ids::<_, Ident>(&v.decls) + // .into_iter() + // .for_each(|ident| { + // // self.add_variable_usage(ident.sym.clone(), ident.sym.clone()); + // }); + // } + // _ => {} + // } + export_decl.visit_children_with(self); + } + + fn visit_named_export(&mut self, named_export: &NamedExport) { + if named_export.src.is_none() { + named_export + .specifiers + .iter() + .for_each(|specifier| match specifier { + ExportSpecifier::Named(named) => { + if let Some(ExtraSpanInfo::AddVariableUsage(sym, usage)) = + self.rewrite_usage_span.get(&named.span) + { + self.add_variable_usage(sym.clone(), InnerGraphMapUsage::Value(usage.clone())); + } + } + _ => unreachable!(), + }); + } + } + fn visit_export_default_expr(&mut self, node: &ExportDefaultExpr) { + if !self.is_enabled() { + return; + } + if let Some(ExtraSpanInfo::AddVariableUsage(sym, usage)) = + self.rewrite_usage_span.get(&node.span) + { + self.add_variable_usage(sym.clone(), InnerGraphMapUsage::Value(usage.clone())); + } + match node.expr { + box Expr::Fn(_) | box Expr::Arrow(_) | box Expr::Lit(_) => { + self.set_symbol_if_is_top_level(DEFAULT_EXPORT.into()); + node.expr.visit_children_with(self); + self.clear_symbol_if_is_top_level(); + } + box Expr::Class(ref class) => { + // TODO: class + class.visit_with(self); + } + _ => { + node.expr.visit_children_with(self); + if is_pure_expression(&node.expr, self.unresolved_ctxt) { + let start = node.expr.span().real_lo(); + let end = node.expr.span().real_hi(); + self.on_usage(Box::new( + move |deps, used_by_exports| match used_by_exports { + Some(UsedByExports::Bool(true)) | None => {} + _ => { + let mut dep = PureExpressionDependency::new(start, end); + dep.used_by_exports = used_by_exports; + deps.push(Box::new(dep)); + } + }, + )); + } + } + } + } + + fn visit_export_default_decl(&mut self, node: &ExportDefaultDecl) { + if !self.is_enabled() { + return; + } + // TODO: + // let symbol: JsWord = "*default*".into(); + match &node.decl { + DefaultDecl::Class(class) => { + // self.visit_class(symbol, &class.class); + class.visit_children_with(self); + } + DefaultDecl::Fn(func) => { + func.visit_with(self); + } + DefaultDecl::TsInterfaceDecl(_) => unreachable!(), + } + } +} + +impl<'a> InnerGraphPlugin<'a> { + pub fn new( + dependencies: &'a mut Vec>, + unresolved_ctxt: SyntaxContext, + top_level_ctxt: SyntaxContext, + rewrite_usage_span: &'a mut HashMap, + import_map: &'a ImportMap, + ) -> Self { + Self { + dependencies, + unresolved_ctxt, + top_level_ctxt, + state: InnerGraphState::default(), + scope_level: 0, + rewrite_usage_span, + import_map, + } + } + + pub fn enable(&mut self) { + self.state.enable = true; + } + + fn is_toplevel(&self) -> bool { + self.scope_level == 0 + } + + fn has_toplevel_symbol(&self) -> bool { + self.state.current_top_level_symbol.is_some() + } + pub fn bailout(&mut self) { + self.state.enable = false; + } + + pub fn is_enabled(&self) -> bool { + self.state.enable + } + + pub fn add_usage(&mut self, symbol: JsWord, usage: InnerGraphMapUsage) { + if !self.is_enabled() { + return; + } + match usage { + InnerGraphMapUsage::True => { + self + .state + .inner_graph + .insert(symbol, InnerGraphMapValue::True); + } + InnerGraphMapUsage::Value(_) | InnerGraphMapUsage::TopLevel(_) => { + // SAFETY: we can make sure that the usage is not a `InnerGraphMapSetValue::True` variant. + let set_value: InnerGraphMapSetValue = usage.into(); + match self.state.inner_graph.entry(symbol) { + Entry::Occupied(mut occ) => { + let val = occ.get_mut(); + match val { + InnerGraphMapValue::Set(set) => { + set.insert(set_value); + } + InnerGraphMapValue::True => { + // do nothing, https://github.com/webpack/webpack/blob/e381884115df2e7b8acd651d3bc2ee6fc35b188e/lib/optimize/InnerGraph.js#L92-L94 + } + InnerGraphMapValue::Nil => { + *val = InnerGraphMapValue::Set(HashSet::from_iter([set_value])); + } + } + } + Entry::Vacant(vac) => { + vac.insert(InnerGraphMapValue::Set(HashSet::from_iter([set_value]))); + } + } + } + } + } + + pub fn add_variable_usage(&mut self, name: JsWord, usage: InnerGraphMapUsage) { + self.add_usage(name, usage); + } + + pub fn on_usage(&mut self, on_usage_callback: UsageCallback) { + if self.is_enabled() { + if let Some(symbol) = self.get_top_level_symbol() { + self + .state + .usage_callback_map + .entry(symbol) + .or_insert(vec![]) + .push(on_usage_callback); + } else { + on_usage_callback(self.dependencies, Some(UsedByExports::Bool(true))); + } + } else { + on_usage_callback(self.dependencies, None); + } + } + + pub fn visit_class_custom(&mut self, symbol: JsWord, class: &Class) { + self.set_top_level_symbol(Some(symbol)); + // `onUsageSuper` + if let Some(box Expr::Ident(ident)) = &class.super_class && is_pure_class(class, self.unresolved_ctxt) { + ident.visit_children_with(self); + // self.on_usage_by_span(Some(symbol), class.span.real_lo(), class.span.real_hi()); + } + self.set_top_level_symbol(None); + } + + pub fn set_top_level_symbol(&mut self, symbol: Option) { + self.state.current_top_level_symbol = symbol; + } + + pub fn set_symbol_if_is_top_level(&mut self, symbol: JsWord) { + if self.is_toplevel() { + self.set_top_level_symbol(Some(symbol)); + } + } + + pub fn clear_symbol_if_is_top_level(&mut self) { + if self.is_toplevel() { + self.set_top_level_symbol(None); + } + } + + pub fn get_top_level_symbol(&self) -> Option { + if self.is_enabled() { + self.state.current_top_level_symbol.clone() + } else { + None + } + } + + pub fn infer_dependency_usage(&mut self) { + // fun will reference it self + if !self.is_enabled() { + return; + } + let state = &mut self.state; + let mut non_terminal = HashSet::from_iter(state.inner_graph.keys().cloned()); + let mut processed: HashMap> = HashMap::default(); + + while !non_terminal.is_empty() { + let mut keys_to_remove = vec![]; + for key in non_terminal.iter() { + let mut new_set = HashSet::default(); + // Using enum to manipulate original is pretty hard, so I use an extra variable to + // flagging the new set has changed to boolean `true` + // you could refer https://github.com/webpack/webpack/blob/ac7e531436b0d47cd88451f497cdfd0dad41535d/lib/optimize/InnerGraph.js#L150 + let mut set_is_true = false; + let mut is_terminal = true; + let already_processed = processed.entry(key.clone()).or_default(); + if let Some(InnerGraphMapValue::Set(names)) = state.inner_graph.get(key) { + for name in names.iter() { + already_processed.insert(name.to_jsword().clone()); + } + for name in names { + match name { + InnerGraphMapSetValue::Str(v) => { + new_set.insert(InnerGraphMapSetValue::Str(v.clone())); + } + InnerGraphMapSetValue::TopLevel(v) => { + let item_value = state.inner_graph.get(v); + match item_value { + Some(InnerGraphMapValue::True) => { + set_is_true = true; + break; + } + Some(InnerGraphMapValue::Set(item_value)) => { + for i in item_value { + if i.to_jsword() == key { + continue; + } + if already_processed.contains(i.to_jsword()) { + continue; + } + new_set.insert(i.clone()); + if matches!(i, InnerGraphMapSetValue::TopLevel(_)) { + is_terminal = false; + } + } + } + _ => {} + } + } + } + } + if set_is_true { + state + .inner_graph + .insert(key.clone(), InnerGraphMapValue::True); + } else if new_set.is_empty() { + state + .inner_graph + .insert(key.clone(), InnerGraphMapValue::Nil); + } else { + state + .inner_graph + .insert(key.clone(), InnerGraphMapValue::Set(new_set)); + } + } + + if is_terminal { + keys_to_remove.push(key.clone()); + // We use `""` to represent global_key + if key == "" { + let global_value = state.inner_graph.get(&JsWord::from("")).cloned(); + if let Some(global_value) = global_value { + for (key, value) in state.inner_graph.iter_mut() { + if key != "" && value != &InnerGraphMapValue::True { + if global_value == InnerGraphMapValue::True { + *value = InnerGraphMapValue::True; + } else { + let mut new_set = match value { + InnerGraphMapValue::Set(set) => std::mem::take(set), + InnerGraphMapValue::True => unreachable!(), + InnerGraphMapValue::Nil => HashSet::default(), + }; + let extend_value = match global_value.clone() { + InnerGraphMapValue::Set(set) => set, + InnerGraphMapValue::True => unreachable!(), + InnerGraphMapValue::Nil => HashSet::default(), + }; + new_set.extend(extend_value); + *value = InnerGraphMapValue::Set(new_set); + } + } + } + } + } + } + } + // Work around for rustc borrow rules + for k in keys_to_remove { + non_terminal.remove(&k); + } + } + + // dbg!(&state.inner_graph); + for (symbol, cbs) in state.usage_callback_map.iter() { + let usage = state.inner_graph.get(symbol); + for cb in cbs { + let used_by_exports = if let Some(usage) = usage { + match usage { + InnerGraphMapValue::Set(set) => { + let finalized_set = + HashSet::from_iter(set.iter().map(|item| item.to_jsword().clone())); + UsedByExports::Set(finalized_set) + } + InnerGraphMapValue::True => UsedByExports::Bool(true), + InnerGraphMapValue::Nil => UsedByExports::Bool(false), + } + } else { + UsedByExports::Bool(false) + }; + + cb(self.dependencies, Some(used_by_exports)); + } + } + } +} diff --git a/crates/rspack_plugin_javascript/src/plugin/mod.rs b/crates/rspack_plugin_javascript/src/plugin/mod.rs index 43a54520384..0150bcaa80c 100644 --- a/crates/rspack_plugin_javascript/src/plugin/mod.rs +++ b/crates/rspack_plugin_javascript/src/plugin/mod.rs @@ -3,8 +3,8 @@ mod flag_dependency_exports_plugin; mod flag_dependency_usage_plugin; pub mod impl_plugin_for_js_plugin; pub mod infer_async_modules_plugin; +pub mod inner_graph_plugin; mod side_effects_flag_plugin; - use std::hash::Hash; pub use flag_dependency_exports_plugin::*; diff --git a/crates/rspack_plugin_javascript/src/plugin/side_effects_flag_plugin.rs b/crates/rspack_plugin_javascript/src/plugin/side_effects_flag_plugin.rs index b660ae69c38..43dfd7a48d9 100644 --- a/crates/rspack_plugin_javascript/src/plugin/side_effects_flag_plugin.rs +++ b/crates/rspack_plugin_javascript/src/plugin/side_effects_flag_plugin.rs @@ -174,14 +174,14 @@ impl SideEffectsFlagPluginVisitor { } } -fn is_pure_expression(expr: &Expr, unresolved_ctxt: SyntaxContext) -> bool { +pub fn is_pure_expression(expr: &Expr, unresolved_ctxt: SyntaxContext) -> bool { !expr.may_have_side_effects(&ExprCtx { unresolved_ctxt, is_unresolved_ref_safe: false, }) } -fn is_pure_decl(stmt: &Decl, unresolved_ctxt: SyntaxContext) -> bool { +pub fn is_pure_decl(stmt: &Decl, unresolved_ctxt: SyntaxContext) -> bool { match stmt { Decl::Class(class) => is_pure_class(&class.class, unresolved_ctxt), Decl::Fn(_) => true, @@ -195,7 +195,7 @@ fn is_pure_decl(stmt: &Decl, unresolved_ctxt: SyntaxContext) -> bool { } } -fn is_pure_class(class: &Class, unresolved_ctxt: SyntaxContext) -> bool { +pub fn is_pure_class(class: &Class, unresolved_ctxt: SyntaxContext) -> bool { if let Some(ref super_class) = class.super_class { if !is_pure_expression(super_class, unresolved_ctxt) { return false; @@ -277,6 +277,3 @@ impl ClassKey for ClassMember { } } } - -#[derive(Debug, Default)] -pub struct SideEffectsFlagPlugin; diff --git a/crates/rspack_plugin_javascript/src/visitors/dependency/harmony_export_dependency_scanner.rs b/crates/rspack_plugin_javascript/src/visitors/dependency/harmony_export_dependency_scanner.rs index 42c39fd4800..17ca1cc4625 100644 --- a/crates/rspack_plugin_javascript/src/visitors/dependency/harmony_export_dependency_scanner.rs +++ b/crates/rspack_plugin_javascript/src/visitors/dependency/harmony_export_dependency_scanner.rs @@ -2,8 +2,9 @@ use rspack_core::{ tree_shaking::symbol::DEFAULT_JS_WORD, BoxDependency, BoxDependencyTemplate, BuildInfo, ConstDependency, SpanExt, }; +use rustc_hash::FxHashMap as HashMap; use swc_core::{ - common::Spanned, + common::{Span, Spanned}, ecma::{ ast::{ ClassDecl, Decl, DefaultDecl, ExportDecl, ExportDefaultDecl, ExportDefaultExpr, @@ -14,7 +15,7 @@ use swc_core::{ }, }; -use super::harmony_import_dependency_scanner::ImportMap; +use super::{harmony_import_dependency_scanner::ImportMap, ExtraSpanInfo}; use crate::dependency::{ AnonymousFunctionRangeInfo, HarmonyExportExpressionDependency, HarmonyExportHeaderDependency, HarmonyExportImportedSpecifierDependency, HarmonyExportSpecifierDependency, Specifier, @@ -26,6 +27,7 @@ pub struct HarmonyExportDependencyScanner<'a> { pub presentational_dependencies: &'a mut Vec, pub import_map: &'a mut ImportMap, pub build_info: &'a mut BuildInfo, + pub rewrite_usage_span: &'a mut HashMap, } impl<'a> HarmonyExportDependencyScanner<'a> { @@ -34,12 +36,14 @@ impl<'a> HarmonyExportDependencyScanner<'a> { presentational_dependencies: &'a mut Vec, import_map: &'a mut ImportMap, build_info: &'a mut BuildInfo, + rewrite_usage_span: &'a mut HashMap, ) -> Self { Self { dependencies, presentational_dependencies, import_map, build_info, + rewrite_usage_span, } } } @@ -60,6 +64,11 @@ impl Visit for HarmonyExportDependencyScanner<'_> { ident.sym.clone(), ident.sym.clone(), ))); + + self.rewrite_usage_span.insert( + export_decl.span(), + ExtraSpanInfo::AddVariableUsage(ident.sym.clone(), ident.sym.clone()), + ); self .build_info .harmony_named_exports @@ -75,6 +84,11 @@ impl Visit for HarmonyExportDependencyScanner<'_> { ident.sym.clone(), ident.sym.clone(), ))); + + self.rewrite_usage_span.insert( + export_decl.span(), + ExtraSpanInfo::AddVariableUsage(ident.sym.clone(), ident.sym.clone()), + ); self.build_info.harmony_named_exports.insert(ident.sym); }); } @@ -115,7 +129,7 @@ impl Visit for HarmonyExportDependencyScanner<'_> { reference.source_order, ids, mode_ids, - Some(export), + Some(export.clone()), false, ))); } else { @@ -125,8 +139,13 @@ impl Visit for HarmonyExportDependencyScanner<'_> { export.clone(), orig.sym.clone(), ))); - self.build_info.harmony_named_exports.insert(export); + + self.build_info.harmony_named_exports.insert(export.clone()); } + self.rewrite_usage_span.insert( + named.span(), + ExtraSpanInfo::AddVariableUsage(orig.sym.clone(), export), + ); } } _ => unreachable!(), @@ -144,6 +163,7 @@ impl Visit for HarmonyExportDependencyScanner<'_> { fn visit_export_default_expr(&mut self, export_default_expr: &'_ ExportDefaultExpr) { // TODO this should be at `HarmonyExportExpressionDependency` + // TODO: add variable usage self .dependencies .push(Box::new(HarmonyExportSpecifierDependency::new( @@ -151,6 +171,10 @@ impl Visit for HarmonyExportDependencyScanner<'_> { DEFAULT_EXPORT.into(), ))); + self.rewrite_usage_span.insert( + export_default_expr.span, + ExtraSpanInfo::AddVariableUsage(DEFAULT_EXPORT.into(), DEFAULT_JS_WORD.clone()), + ); self .presentational_dependencies .push(Box::new(HarmonyExportExpressionDependency::new( @@ -169,16 +193,21 @@ impl Visit for HarmonyExportDependencyScanner<'_> { }; // TODO this should be at `HarmonyExportExpressionDependency` + + let local = match &ident { + Some(ident) => ident.sym.clone(), + None => DEFAULT_EXPORT.into(), + }; self .dependencies .push(Box::new(HarmonyExportSpecifierDependency::new( DEFAULT_JS_WORD.clone(), - match &ident { - Some(ident) => ident.sym.clone(), - None => DEFAULT_EXPORT.into(), - }, + local.clone(), ))); - + self.rewrite_usage_span.insert( + export_default_decl.span, + ExtraSpanInfo::AddVariableUsage(local, DEFAULT_JS_WORD.clone()), + ); self .presentational_dependencies .push(Box::new(HarmonyExportExpressionDependency::new( diff --git a/crates/rspack_plugin_javascript/src/visitors/dependency/harmony_import_dependency_scanner.rs b/crates/rspack_plugin_javascript/src/visitors/dependency/harmony_import_dependency_scanner.rs index e5357a9b680..cfc44504e84 100644 --- a/crates/rspack_plugin_javascript/src/visitors/dependency/harmony_import_dependency_scanner.rs +++ b/crates/rspack_plugin_javascript/src/visitors/dependency/harmony_import_dependency_scanner.rs @@ -17,7 +17,7 @@ use swc_core::{ }, }; -use super::collect_destructuring_assignment_properties; +use super::{collect_destructuring_assignment_properties, ExtraSpanInfo}; use crate::dependency::{ HarmonyExportImportedSpecifierDependency, HarmonyImportSideEffectDependency, HarmonyImportSpecifierDependency, Specifier, @@ -73,6 +73,7 @@ pub struct HarmonyImportDependencyScanner<'a> { pub import_map: &'a mut ImportMap, pub imports: Imports, pub build_info: &'a mut BuildInfo, + pub rewrite_usage_span: &'a mut HashMap, last_harmony_import_order: i32, } @@ -82,6 +83,7 @@ impl<'a> HarmonyImportDependencyScanner<'a> { presentational_dependencies: &'a mut Vec, import_map: &'a mut ImportMap, build_info: &'a mut BuildInfo, + rewrite_usage_span: &'a mut HashMap, ) -> Self { Self { dependencies, @@ -89,6 +91,7 @@ impl<'a> HarmonyImportDependencyScanner<'a> { import_map, imports: Default::default(), build_info, + rewrite_usage_span, last_harmony_import_order: 0, } } @@ -130,6 +133,7 @@ impl Visit for HarmonyImportDependencyScanner<'_> { Specifier::Named(orig, exported) => { let name = exported.clone().unwrap_or(orig.clone()); let ids = vec![(name.clone(), Some(orig.clone()))]; + // TODO: add variable usage self .dependencies .push(Box::new(HarmonyExportImportedSpecifierDependency::new( @@ -172,6 +176,7 @@ impl Visit for HarmonyImportDependencyScanner<'_> { program.visit_children_with(&mut HarmonyImportRefDependencyScanner::new( self.import_map, self.dependencies, + self.rewrite_usage_span, )); } @@ -337,15 +342,21 @@ pub struct HarmonyImportRefDependencyScanner<'a> { pub import_map: &'a ImportMap, pub dependencies: &'a mut Vec, pub properties_in_destructuring: HashMap>, + pub rewrite_usage_span: &'a mut HashMap, } impl<'a> HarmonyImportRefDependencyScanner<'a> { - pub fn new(import_map: &'a ImportMap, dependencies: &'a mut Vec) -> Self { + pub fn new( + import_map: &'a ImportMap, + dependencies: &'a mut Vec, + rewrite_usage_span: &'a mut HashMap, + ) -> Self { Self { import_map, dependencies, enter_callee: false, properties_in_destructuring: HashMap::default(), + rewrite_usage_span, } } } @@ -368,6 +379,9 @@ impl Visit for HarmonyImportRefDependencyScanner<'_> { fn visit_prop(&mut self, n: &Prop) { match n { Prop::Shorthand(shorthand) => { + self + .rewrite_usage_span + .insert(shorthand.span, ExtraSpanInfo::ReWriteUsedByExports); if let Some(reference) = self.import_map.get(&shorthand.to_id()) { self .dependencies @@ -391,6 +405,9 @@ impl Visit for HarmonyImportRefDependencyScanner<'_> { fn visit_ident(&mut self, ident: &Ident) { if let Some(reference) = self.import_map.get(&ident.to_id()) { + self + .rewrite_usage_span + .insert(ident.span, ExtraSpanInfo::ReWriteUsedByExports); self .dependencies .push(Box::new(HarmonyImportSpecifierDependency::new( @@ -425,6 +442,9 @@ impl Visit for HarmonyImportRefDependencyScanner<'_> { if let Some(prop) = prop { let mut ids = reference.names.clone().map(|f| vec![f]).unwrap_or_default(); ids.push(prop); + self + .rewrite_usage_span + .insert(member_expr.span, ExtraSpanInfo::ReWriteUsedByExports); self .dependencies .push(Box::new(HarmonyImportSpecifierDependency::new( diff --git a/crates/rspack_plugin_javascript/src/visitors/dependency/mod.rs b/crates/rspack_plugin_javascript/src/visitors/dependency/mod.rs index 6cb7c6fde72..8bb66794d5a 100644 --- a/crates/rspack_plugin_javascript/src/visitors/dependency/mod.rs +++ b/crates/rspack_plugin_javascript/src/visitors/dependency/mod.rs @@ -7,7 +7,7 @@ mod context_helper; mod export_info_api_scanner; mod harmony_detection_scanner; mod harmony_export_dependency_scanner; -mod harmony_import_dependency_scanner; +pub mod harmony_import_dependency_scanner; mod hot_module_replacement_scanner; mod import_meta_scanner; mod import_scanner; @@ -20,9 +20,13 @@ use rspack_core::{ ast::javascript::Program, BoxDependency, BoxDependencyTemplate, BuildInfo, BuildMeta, CompilerOptions, ModuleIdentifier, ModuleType, ResourceData, }; +use rustc_hash::FxHashMap as HashMap; +use swc_core::common::Span; use swc_core::common::{comments::Comments, Mark, SyntaxContext}; +use swc_core::ecma::atoms::JsWord; pub use util::*; +use self::harmony_import_dependency_scanner::ImportMap; use self::{ api_scanner::ApiScanner, common_js_export_scanner::CommonJsExportDependencyScanner, common_js_import_dependency_scanner::CommonJsImportDependencyScanner, @@ -36,8 +40,22 @@ use self::{ node_stuff_scanner::NodeStuffScanner, require_context_scanner::RequireContextScanner, url_scanner::UrlScanner, worker_scanner::WorkerScanner, }; -pub type ScanDependenciesResult = (Vec, Vec); +pub struct ScanDependenciesResult { + pub dependencies: Vec, + pub presentational_dependencies: Vec, + // TODO: rename this name + pub rewrite_usage_span: HashMap, + pub import_map: ImportMap, +} + +#[derive(Debug, Clone)] +pub enum ExtraSpanInfo { + ReWriteUsedByExports, + // (symbol, usage) + // (local, exported) refer https://github.com/webpack/webpack/blob/ac7e531436b0d47cd88451f497cdfd0dad41535d/lib/javascript/JavascriptParser.js#L2347-L2352 + AddVariableUsage(JsWord, JsWord), +} #[allow(clippy::too_many_arguments)] pub fn scan_dependencies( program: &Program, @@ -54,6 +72,8 @@ pub fn scan_dependencies( let unresolved_ctxt = SyntaxContext::empty().apply_mark(unresolved_mark); let comments = program.comments.clone(); let mut parser_exports_state = None; + + let mut rewrite_usage_span = HashMap::default(); program.visit_with(&mut ApiScanner::new( &unresolved_ctxt, resource_data, @@ -101,6 +121,8 @@ pub fn scan_dependencies( } } + let mut import_map = Default::default(); + if module_type.is_js_auto() || module_type.is_js_esm() { program.visit_with(&mut HarmonyDetectionScanner::new( build_info, @@ -108,18 +130,19 @@ pub fn scan_dependencies( module_type, &mut presentational_dependencies, )); - let mut import_map = Default::default(); program.visit_with(&mut HarmonyImportDependencyScanner::new( &mut dependencies, &mut presentational_dependencies, &mut import_map, build_info, + &mut rewrite_usage_span, )); program.visit_with(&mut HarmonyExportDependencyScanner::new( &mut dependencies, &mut presentational_dependencies, &mut import_map, build_info, + &mut rewrite_usage_span, )); let mut worker_syntax_scanner = rspack_core::needs_refactor::WorkerSyntaxScanner::new( rspack_core::needs_refactor::DEFAULT_WORKER_SYNTAX, @@ -156,5 +179,10 @@ pub fn scan_dependencies( )); } - (dependencies, presentational_dependencies) + ScanDependenciesResult { + dependencies, + presentational_dependencies, + rewrite_usage_span, + import_map, + } } diff --git a/crates/rspack_plugin_wasm/src/dependency.rs b/crates/rspack_plugin_wasm/src/dependency.rs index 07e58a3a89d..71b8ef5188b 100644 --- a/crates/rspack_plugin_wasm/src/dependency.rs +++ b/crates/rspack_plugin_wasm/src/dependency.rs @@ -46,6 +46,10 @@ impl Dependency for WasmImportDependency { fn dependency_type(&self) -> &DependencyType { &DependencyType::WasmImport } + + fn span(&self) -> Option { + self.span + } } impl ModuleDependency for WasmImportDependency { @@ -57,10 +61,6 @@ impl ModuleDependency for WasmImportDependency { &self.request } - fn span(&self) -> Option<&ErrorSpan> { - self.span.as_ref() - } - fn set_request(&mut self, request: String) { self.request = request; } diff --git a/crates/rspack_testing/src/test_config.rs b/crates/rspack_testing/src/test_config.rs index fc6dfa5f822..134486a931a 100644 --- a/crates/rspack_testing/src/test_config.rs +++ b/crates/rspack_testing/src/test_config.rs @@ -125,6 +125,8 @@ pub struct Optimization { pub side_effects: String, #[serde(default = "true_by_default")] pub provided_exports: bool, + #[serde(default = "true_by_default")] + pub inner_graph: bool, #[serde(default = "default_optimization_false_string_lit")] pub used_exports: String, } @@ -442,6 +444,7 @@ impl TestConfig { remove_empty_chunks: self.optimization.remove_empty_chunks, side_effects: c::SideEffectOption::from(self.optimization.side_effects.as_str()), provided_exports: self.optimization.provided_exports, + inner_graph: self.optimization.inner_graph, used_exports: c::UsedExportsOption::from(self.optimization.used_exports.as_str()), }, profile: false, diff --git a/packages/rspack/src/config/adapter.ts b/packages/rspack/src/config/adapter.ts index c1fd12afc27..fed204ab64e 100644 --- a/packages/rspack/src/config/adapter.ts +++ b/packages/rspack/src/config/adapter.ts @@ -664,8 +664,9 @@ function getRawOptimization( !isNil(optimization.sideEffects) && !isNil(optimization.realContentHash) && !isNil(optimization.providedExports) && - !isNil(optimization.usedExports), - "optimization.moduleIds, optimization.removeAvailableModules, optimization.removeEmptyChunks, optimization.sideEffects, optimization.realContentHash, optimization.providedExports, optimization.usedExports should not be nil after defaults" + !isNil(optimization.usedExports) && + !isNil(optimization.innerGraph), + "optimization.moduleIds, optimization.removeAvailableModules, optimization.removeEmptyChunks, optimization.sideEffects, optimization.realContentHash, optimization.providedExports, optimization.usedExports, optimization.innerGraph should not be nil after defaults" ); return { chunkIds: optimization.chunkIds, @@ -676,7 +677,8 @@ function getRawOptimization( sideEffects: String(optimization.sideEffects), realContentHash: optimization.realContentHash, usedExports: String(optimization.usedExports), - providedExports: optimization.providedExports + providedExports: optimization.providedExports, + innerGraph: optimization.innerGraph }; } diff --git a/packages/rspack/src/config/defaults.ts b/packages/rspack/src/config/defaults.ts index e97cfd8d345..c998e65bb97 100644 --- a/packages/rspack/src/config/defaults.ts +++ b/packages/rspack/src/config/defaults.ts @@ -687,6 +687,7 @@ const applyOptimizationDefaults = ( F(optimization, "sideEffects", () => (production ? true : "flag")); D(optimization, "providedExports", true); D(optimization, "usedExports", production); + D(optimization, "innerGraph", production); D(optimization, "runtimeChunk", false); D(optimization, "realContentHash", production); D(optimization, "minimize", production); diff --git a/packages/rspack/src/config/zod.ts b/packages/rspack/src/config/zod.ts index da3eaf9d0b9..0222173faf0 100644 --- a/packages/rspack/src/config/zod.ts +++ b/packages/rspack/src/config/zod.ts @@ -936,6 +936,7 @@ const optimization = z.strictObject({ realContentHash: z.boolean().optional(), sideEffects: z.enum(["flag"]).or(z.boolean()).optional(), providedExports: z.boolean().optional(), + innerGraph: z.boolean().optional(), usedExports: z.enum(["global"]).or(z.boolean()).optional() }); export type Optimization = z.infer; diff --git a/packages/rspack/tests/Defaults.unittest.ts b/packages/rspack/tests/Defaults.unittest.ts index 5194ba92168..2c22263c822 100644 --- a/packages/rspack/tests/Defaults.unittest.ts +++ b/packages/rspack/tests/Defaults.unittest.ts @@ -108,7 +108,9 @@ describe("snapshots", () => { - "mode": "none", + "mode": undefined, @@ ... @@ + - "innerGraph": false, - "minimize": false, + + "innerGraph": true, + "minimize": true, @@ ... @@ - "moduleIds": "named", @@ -147,7 +149,9 @@ describe("snapshots", () => { - "mode": "none", + "mode": "production", @@ ... @@ + - "innerGraph": false, - "minimize": false, + + "innerGraph": true, + "minimize": true, @@ ... @@ - "moduleIds": "named", diff --git a/packages/rspack/tests/__snapshots__/Defaults.unittest.ts.snap b/packages/rspack/tests/__snapshots__/Defaults.unittest.ts.snap index 679f21564e7..73235a34a21 100644 --- a/packages/rspack/tests/__snapshots__/Defaults.unittest.ts.snap +++ b/packages/rspack/tests/__snapshots__/Defaults.unittest.ts.snap @@ -186,6 +186,7 @@ exports[`snapshots should have the correct base config 1`] = ` }, "optimization": { "chunkIds": "named", + "innerGraph": false, "minimize": false, "minimizer": [], "moduleIds": "named",