CC 4.0 协议声明 本节内容派生于以下链接指向的内容 ,并遵守 CC BY 4.0 许可证的规定。
以下内容如果没有特殊声明,可以认为都是基于原内容的修改和删减后的结果。
 
Tree shaking 
Rspack 支持 tree shaking,这是在 JavaScript 上下文中常用的术语,用于描述死代码的删除。
它依赖于 import 和 export 语句来检测代码模块是否被导出和导入以在 JavaScript 文件之间使用。
当你将 mode 设置为 production 时,Rspack 将默认启用 tree shaking。
Basic tree shaking 
rspack.config.js
/**
  * @type {import('@rspack/core').Configuration}
  */ 
 const  config  =   { 
    mode :   'development' , 
    entry :   { 
      index :   './src/index.js' , 
    } , 
    output :   { } , 
 } ; 
 
 module . exports  =  config ;  
./src/index.js
import   {  cube  }   from   './math.js' ; 
 
 function   component ( )   { 
    const  element  =  document . createElement ( 'pre' ) ; 
 
   element . innerHTML  =   [ 'Hello webpack!' ,   '5 cubed is equal to '   +   cube ( 5 ) ] . join ( 
      '\n\n' 
    ) ; 
 
    return  element ; 
 } 
 
 document . body . appendChild ( component ( ) ) ;  
./src/math.js
export   function   square ( x )   { 
    return  x  *  x ; 
 } 
 
 export   function   cube ( x )   { 
    return  x  *  x  *  x ; 
 }  
注意到,我们没有从 src/math.js  模块导入 square 方法。该函数是“死代码”,表示应该被删除的未使用的导出。现在构建我们的项目
将产生以下构建结果:
// ... 省略一些不重要的代码 
 var  __webpack_modules__  =   { 
    './src/index.js' :   function   ( module ,  exports ,  __webpack_require__ )   { 
      'use strict' ; 
     Object . defineProperty ( exports ,   '__esModule' ,   { 
        value :   true , 
      } ) ; 
      var  _mathJs  =   __webpack_require__ ( './src/math.js' ) ; 
      function   component ( )   { 
        const  element  =  document . createElement ( 'pre' ) ; 
       element . innerHTML  =   [ 
          'Hello webpack!' , 
          '5 cubed is equal to '   +   ( 0 ,  _mathJs . cube ) ( 5 ) , 
        ] . join ( '\n\n' ) ; 
        return  element ; 
      } 
     document . body . appendChild ( component ( ) ) ; 
    } , 
    './src/math.js' :   function   ( module ,  exports ,  __webpack_require__ )   { 
      'use strict' ; 
     Object . defineProperty ( exports ,   '__esModule' ,   { 
        value :   true , 
      } ) ; 
      function   _export ( target ,  all )   { 
        for   ( var  name  in  all ) 
         Object . defineProperty ( target ,  name ,   { 
            enumerable :   true , 
            get :  all [ name ] , 
          } ) ; 
      } 
      _export ( exports ,   { 
        square :   function   ( )   { 
          return  square ; 
        } , 
        cube :   function   ( )   { 
          return  cube ; 
        } , 
      } ) ; 
      function   square ( x )   { 
        return  x  *  x ; 
      } 
      function   cube ( x )   { 
        return  x  *  x  *  x ; 
      } 
    } , 
 } ; 
 // ...  
正如你所看到的,如果我们不启用 treeShaking,所有代码都保持不变,只是将代码包裹了一层运行时代码。
现在,我们切换到 production 模式,重新构建项目,为了让产物更加可读,我们同时关闭 minimize 选项 以及切换 moduleIds 为 named,为了和后面章节对比,我们关闭 optimization.sideEffects。
rspack.config.js
/**
   * @type {import('@rspack/core').Configuration}
   */
 const config = {
    mode: 'production',
    entry: {
      index: './src/index.js',
    },
 +  optimization: {
 +    sideEffects: false,
 +    moduleIds: 'named',
 +    minimize: false
 +  }
 };
 
 module.exports = config;  
重新构建项目后,square 函数将会被删除。
SideEffects 
在一个 100% ESM 模块化的世界里,识别副作用是比较直接的。然而,我们还没有达到那个阶段 (在实际的生产代码中有各种格式的代码混用,cjs、esm 和 umd 等等),所以在此期间,需要在你的代码中提供“纯度”方面的提示给 Rspack 的编译器。
该功能通常由 "sideEffects" package.json 属性来完成的。
package.json
{ 
    "name" :   "your-project" , 
    "sideEffects" :   false 
 }  
sideEffects 字段支持以下值:
false  这个包中的所有文件都没有副作用。 
string  匹配包含副作用文件的 glob。 
Array<string>  匹配包含副作用文件的 glob 数组。 
undefined  当你不设置 package.json 的 sideEffects 时的默认值。当 optimization.sideEffects 为 true 时,Rspack 将尝试分析代码是否具有副作用,当 optimization.sideEffects 为 'flag' 时,Rspack 将默认包中的所有模块均有副作用。 
 
这次,我们使用一个更复杂的示例。
rspack.config.js
/**
  * @type {import('@rspack/core').Configuration}
  */ 
 const  config  =   { 
    mode :   'production' , 
    entry :   { 
      index :   './src/index.js' , 
    } , 
    optimization :   { 
      moduleIds :   'named' , 
      minimize :   false , 
    } , 
 } ; 
 module . exports  =  config ;  
index.js
import   {  multiply  }   from   'math' ; 
 
 console . log ( multiply ( 2 ,   3 ) ) ;  
node_modules/math/package.json
{ 
    "name" :   "math" , 
    "sideEffects" :   false 
 }  
node_modules/math/index.js
export   *   from   './add.js' ; 
 export   *   from   './multiply.js' ; 
 export   *   from   './subtract.js' ;  
node_modules/math/subtract.js
export   const   subtract   =   ( a ,  b )   =>  a  -  b ;  
node_modules/math/multiply.js
export   const   multiply   =   ( a ,  b )   =>  a  *  b ;  
node_modules/math/add.js
const  randomDate  =  Date . now ( ) ; 
 export   const   addRandomDate   =   ( a )   =>  a  +  randomDate ; 
 export   const   add   =   ( a ,  b )   =>  a  +  b ;  
变量 randomDate 在默认情况下是需要被保留的,因为它在模块初始化时期包含副作用。
但是,由于 package.json 中包含了 sideEffects 字段,且值为 false,除此之外在 add.js 中没有使用任何导出变量,因此整个模块都可以被跳过,subtract.js 同理。
//... 
 var  __webpack_modules__  =   { 
    './node_modules/math/index.js' :   function   ( 
      module , 
     exports , 
     __webpack_require__ 
    )   { 
      'use strict' ; 
     Object . defineProperty ( exports ,   '__esModule' ,   { 
        value :   true , 
      } ) ; 
     __webpack_require__ . es ( 
        __webpack_require__ ( './node_modules/math/multiply.js' ) , 
       exports
      ) ; 
    } , 
    './node_modules/math/multiply.js' :   function   ( 
      module , 
     exports , 
     __webpack_require__ 
    )   { 
      'use strict' ; 
     Object . defineProperty ( exports ,   '__esModule' ,   { 
        value :   true , 
      } ) ; 
     Object . defineProperty ( exports ,   'multiply' ,   { 
        enumerable :   true , 
        get :   function   ( )   { 
          return  multiply ; 
        } , 
      } ) ; 
      const   multiply   =   ( a ,  b )   =>  a  *  b ; 
    } , 
    './src/index.js' :   function   ( module ,  exports ,  __webpack_require__ )   { 
      'use strict' ; 
     Object . defineProperty ( exports ,   '__esModule' ,   { 
        value :   true , 
      } ) ; 
      var  _indexJs  =   __webpack_require__ ( './node_modules/math/index.js' ) ; 
     console . log ( ( 0 ,  _indexJs . multiply ) ( 2 ,   3 ) ) ; 
    } , 
 } ; 
 // ...  
module.rule.sideEffects 
你可以使用 module.rule.sideEffects 覆盖某些模块的 sideEffects 选项。
为什么我们需要这样的功能呢?我们仍然使用上面的例子,假设 math 包的作者忘记在 package.json 中添加 sideEffects 选项:
node_modules/math/package.json
{
 +  "name": "math"
 -  "name": "math",
 -  "sideEffects": false
 }  
Rspack 将尝试安全地分析代码,并仅在所有顶级语句均没有副作用时标记模块为无副作用。
正如我们所看到的,math/index.js 、math/subtract.js  和 math/multiply.js  都没有副作用,而 math/add.js 不是,因为 const randomDate = Date.now() 含有副作用。当我们重新构建项目时,你可以看到差异如下:
//...
 var __webpack_modules__ = {
 "./node_modules/math/index.js": function (module, exports, __webpack_require__) {
 "use strict";
 Object.defineProperty(exports, "__esModule", {
      value: true
 });
 __webpack_require__.es(__webpack_require__("./node_modules/math/multiply.js"), exports);
 + __webpack_require__.es(__webpack_require__("./node_modules/math/add.js"), exports);
 },
 "./node_modules/math/multiply.js": function (module, exports, __webpack_require__) {
 "use strict";
 Object.defineProperty(exports, "__esModule", {
      value: true
 });
 Object.defineProperty(exports, "multiply", {
      enumerable: true,
      get: function() {
          return multiply;
      }
 });
 const multiply = (a, b)=>a * b;
 },
 + "./node_modules/math/add.js": function (module, exports, __webpack_require__) {
 +  "use strict";
 +  Date.now()
 + },
 "./src/index.js": function (module, exports, __webpack_require__) {
 "use strict";
 Object.defineProperty(exports, "__esModule", {
      value: true
 });
 var _indexJs = __webpack_require__("./node_modules/math/index.js");
 console.log((0, _indexJs.multiply)(2, 3));
 },
 
 }
 // ...  
由于module.rule.sideEffects 比 package.json 中的 sideEffects 优先级更高,我们可以使用 module.rule.sideEffects 来覆盖某些模块的 sideEffects 标识.
由于初始化的副作用只在使用 addRandomDate 时才有意义,因此我们可以安全地覆盖它。为此,我们可以对 rspack.config.js 进行以下修改:
rspack.config.js
/**
   * @type {import('@rspack/core').Configuration}
   */
 const config = {
    mode: 'production',
    entry: {
      index: './src/index.js',
    },
    optimization: {
      minimize: false,
      moduleIds: 'named'
    },
 +   module: {
 +     rules: [
 +       {
 +         test: /math\/add\.js/,
 +         sideEffects: false
 +       }
 +     ]
 +   }
 };
 module.exports = config;  
重新构建项目,我们得到和之前相同的结果,整个 math/add.js  模块都被删除了。