CC 4.0 协议声明

本节内容派生于以下链接指向的内容 ,并遵守 CC BY 4.0 许可证的规定。

以下内容如果没有特殊声明,可以认为都是基于原内容的修改和删减后的结果。

模块方法

当使用 Rspack 打包应用程序时,你可以选择多种模块语法风格,包括 ES6、CommonJS。

尽管 Rspack 支持多种模块语法,我们建议为了保持一致性并避免奇怪的 bug,最好遵循单一的语法。

ES6 (推荐)

Rspack 原生支持 ES6 模块语法,可以使用静态的 importexportimport() 语法。

import

静态 import 另一个模块的 export

import MyModule from './my-module.js';
import { NamedExport } from './other-module.js';

你还可以 import Data URI:

import 'data:text/javascript;charset=utf-8;base64,Y29uc29sZS5sb2coJ2lubGluZSAxJyk7';
import {
  number,
  fn,
} from 'data:text/javascript;charset=utf-8;base64,ZXhwb3J0IGNvbnN0IG51bWJlciA9IDQyOwpleHBvcnQgY29uc3QgZm4gPSAoKSA9PiAiSGVsbG8gd29ybGQiOw==';

export

将任何内容作为默认导出或具名导出。

// 具名导出
export var Count = 5;
export function Multiply(a, b) {
  return a * b;
}

// 默认导出
export default {
  // Some data...
};

动态 import()

function import(path: string): Promise;

动态加载模块。对 import() 的调用被视为分割点,这意味着请求的模块及其子模块被拆分成单独的 chunk。

if (module.hot) {
  import('lodash').then(_ => {
    // 使用 lodash 做些事情...
  });
}
警告

此功能内部依赖于 Promise。如果你在旧版浏览器中使用 import(),请记得使用类似于 es6-promisepromise-polyfill 的 polyfill 来模拟 Promise

import() 中的动态表达式

无法使用完全动态的导入语句,例如 import(foo)。因为 foo 可能是系统或项目中任何文件的任何路径。

import() 必须至少包含一些关于模块所在位置的信息。可以将打包限制在特定目录或一组文件中,这样当你使用动态表达式时 - 在 import() 调用中可能被请求的每个模块都会被包括进来。 例如,import(./locale/${language}.json) 会将 ./locale 目录中的每个 .json 文件都被打包进新的代码块。在运行时,一旦变量 language 被计算出来,任何像 english.jsongerman.json 这样的文件都将可供使用。

// 想象一下,如果我们有一种方法可以从 Cookie 或其他存储中获取语言
const language = detectVisitorLanguage();
import(`./locale/${language}.json`).then(module => {
  // 做一些翻译相关的事情
});

Magic Comments

通过向 import 语句添加注释,我们可以执行诸如命名 chunk 或选择不同模式等操作。有关这些魔法注释的完整列表,请参见下面的代码,以及对这些注释功能的解释。

import(
  /* webpackChunkName: "my-chunk-name" */
  /* webpackPrefetch: true */
  /* webpackPreload: true */
  'module'
);

webpackChunkName:新 chunk 的名称。

webpackPrefetch:告诉浏览器将来可能需要该资源来进行某些导航跳转(0.4.5 及以上版本支持)。

webpackPreload:告诉浏览器在当前导航期间可能需要该资源(0.4.5 及以上版本支持)。

CommonJS

Rspack 也支持 CommonJS 语法,可以使用 requiremodule.exports 语法。

Data URI 模块

Rspack 支持使用 importrequire 语法导入 Data URI 模块。

import

import DataURI from 'data:text/javascript,export default 42';

require

require('data:text/javascript,module.exports = 42');

除此之外,还支持了 Base64 编码:

const {
  number,
  fn,
} = require('data:text/javascript;charset=utf-8;base64,ZXhwb3J0IGNvbnN0IG51bWJlciA9IDQyOwpleHBvcnQgZnVuY3Rpb24gZm4oKSB7CiAgcmV0dXJuICJIZWxsbyB3b3JsZCI7Cn0=');
TIP

Data URI 模块可以被用作虚拟模块(Virtual Modules)的实现方式,如:配合 loader 完成运行时动态加载自定义模块。

Webpack specific

除了上述的模块方法之外,Rspack 还支持一些 webpack 特有的方法。

require.context

require.context 是 webpack 中的一个特殊函数,它允许你动态地 context 一组模块。

Rspack 会在构建过程中解析代码里的 require.context()

  • 类型:
function requireContext(
  /**
   * 要搜索的目录
   */
  directory: string,
  /**
   * 是否还搜索其子目录
   * @default true
   */
  includeSubdirs?: boolean,
  /**
   * 匹配文件的正则表达式
   * @default /^\.\/.*$/(匹配任意文件)
   */
  filter?: RegExp,
  /**
   * 模块加载模式
   * @default 'sync'
   */
  mode?: 'sync' | 'eager' | 'weak' | 'lazy' | 'lazy-once',
): Context;
  • 示例:
// 创建一个上下文,
// 文件直接来自 test 目录,匹配的文件名以 `.test.js` 结尾。
const context = require.context('./test', false, /\.test\.js$/);
// 创建一个上下文,
// 文件来自父文件夹及其所有子级文件夹,匹配的文件名以 `.stories.js` 结尾。
const context = require.context('../', true, /\.stories\.js$/);
// 如果 `mode` 被设置为 `lazy`,模块将会被异步加载
const context = require.context('./locales', true, /\.json$/, 'lazy');

传递给 require.context() 的参数必须是字面量。

context API

require.context() 返回的 context 是一个函数,它接收一个 request 参数(模块路径)。

这个函数有三个属性:resolvekeysid

  • resolve 是一个函数,它返回 request 被解析后得到的模块 id。
  • keys 也是一个函数,它返回一个数组,由所有可能被此上下文模块处理的请求组成。
  • id 是上下文模块的模块 id. 它可能在使用 module.hot.accept 时会用到。

如果你想引入一个文件夹下面的所有文件,或者引入能匹配一个正则表达式的所有文件,这个功能就会很有帮助。

考虑一种情况,你有一个这样的文件夹结构:

src ├── components │ ├── Button.js │ ├── Header.js │ └── Footer.js

你可以使用 require.context() 动态导入文件夹中的所有组件:

const componentsContext = require.context('./components', false, /\.js$/);

componentsContext.keys().forEach(fileName => {
  const componentModule = componentsContext(fileName);

  // 在这里你可以使用你的模块,例如使用 console.log 输出
  console.log(componentModule);
});

require.context() 简化了模块导入过程,尤其是当你有大量模块需要管理时。在使用时,请避免匹配到不需要的文件,否则可能导致构建时间和产物体积明显增加。