本节涵盖了在 webpack 编译的代码中可用的所有方法。使用 webpack 打包应用程序时,您可以选择多种模块语法样式,包括 ES6、CommonJS 和 AMD。
尽管 webpack 支持多种模块语法,但我们建议为了一致性并避免异常行为/错误,只遵循一种语法。实际上,当 `.mjs` 文件、`.cjs` 文件或 `.js` 文件最近的父级 `package.json` 文件包含值为 `"module"` 或 `"commonjs"` 的 `"type"` 字段时,webpack 会强制执行此建议。请在阅读下文之前注意这些强制规定。
webpack 的第 2 版原生支持 ES6 模块语法,这意味着你可以直接使用 `import` 和 `export`,而无需像 Babel 这样的工具来处理。请记住,你可能仍然需要 Babel 来处理其他 ES6+ 特性。webpack 支持以下方法:
静态地 `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==';
将任何内容作为 `default` 或命名导出。
// Named exports
export var Count = 5;
export function Multiply(a, b) {
return a * b;
}
// Default export
export default {
// Some data...
};
function(string path):Promise
动态加载模块。`import()` 调用被视为分割点,这意味着请求的模块及其子模块将被分割成一个单独的 chunk。
if (module.hot) {
import('lodash').then((_) => {
// Do something with lodash (a.k.a '_')...
});
}
无法使用完全动态的 import 语句,例如 `import(foo)`。因为 `foo` 可能指向你系统或项目中的任何文件。
`import()` 必须至少包含一些关于模块位置的信息。打包可以限制在特定的目录或文件集内,这样当你使用动态表达式时——在 `import()` 调用中可能被请求的每个模块都会被包含进来。例如,`import(`./locale/${language}.json`)` 将导致 `./locale` 目录中的所有 `.json` 文件被打包到一个新的 chunk 中。在运行时,当变量 `language` 被计算出来后,任何文件(如 `english.json` 或 `german.json`)都将可供使用。
// imagine we had a method to get language from cookies or other storage
const language = detectVisitorLanguage();
import(`./locale/${language}.json`).then((module) => {
// do something with the translations
});
内联注释可使功能生效。通过在 import 中添加注释,我们可以做一些事情,例如命名我们的 chunk 或选择不同的模式。有关这些魔法注释的完整列表,请参阅下面的代码,然后是这些注释功能的解释。
// Single target
import(
/* webpackChunkName: "my-chunk-name" */
/* webpackMode: "lazy" */
/* webpackExports: ["default", "named"] */
/* webpackFetchPriority: "high" */
'module'
);
// Multiple possible targets
import(
/* webpackInclude: /\.json$/ */
/* webpackExclude: /\.noimport\.json$/ */
/* webpackChunkName: "my-chunk-name" */
/* webpackMode: "lazy" */
/* webpackPrefetch: true */
/* webpackPreload: true */
`./locale/${language}`
);
import(/* webpackIgnore: true */ 'ignored-module.js');
JavaScript 用法
当设置为 `true` 时,禁用动态 import 解析。
当使用 `import.meta.url` 时,它不会保持原样;相反,它会根据 `baseURI` 进行替换。对于模块,它被替换为 `new URL("./", import.meta.url)`,对于其他情况,它默认为 `document.baseURI`。这确保了相对 URL 正常工作,与基本 URL 上下文对齐。
import(/* webpackIgnore: true */ 'ignored-module.js');
new URL(/* webpackIgnore: true */ 'file1.css', import.meta.url);
CSS 用法
`webpackIgnore` 注释可以控制 webpack 是否处理特定的 import 或 URL 引用。在某些情况下它开箱即用,但由于性能原因,默认情况下**不支持所有情况**。
我们在以下情况支持 `webpackIgnore`
@import /* webpackIgnore: false */ url(./basic.css);
.class {
color: red;
background: /* webpackIgnore: true */ url('./url/img.png');
}
.class {
background-image: image-set(
/*webpackIgnore: true*/ url(./url/img1x.png) 1x,
url(./url/img2x.png) 2x,
url(./url/img3x.png) 3x
);
}
新 chunk 的名称。自 webpack 2.6.0 起,在给定字符串中支持占位符 `[index]` 和 `[request]`,分别表示递增的数字或实际解析的文件名。添加此注释将使我们单独的 chunk 命名为 [my-chunk-name].js 而不是 [id].js。
为特定的动态 import 设置 `fetchPriority`。也可以通过使用 `module.parser.javascript.dynamicImportFetchPriority` 选项为所有动态 import 设置一个全局默认值。
import(
/* webpackFetchPriority: "high" */
'path/to/module'
);
自 webpack 2.6.0 起,可以指定不同的模式来解析动态 import。支持以下选项:
告诉浏览器将来某个导航可能需要此资源。查看指南以获取有关 webpackPrefetch 如何工作的更多信息。
告诉浏览器当前导航可能需要此资源。查看指南以获取有关 webpackPreload 如何工作的更多信息。
一个正则表达式,在 import 解析期间将进行匹配。只有匹配的模块**才会被打包**。
一个正则表达式,在 import 解析期间将进行匹配。任何匹配的模块**都不会被打包**。
告诉 webpack 只打包动态 `import()` 模块的指定导出。这可以减小 chunk 的输出大小。自 webpack 5.0.0-beta.18 起可用。
CommonJS 的目标是为浏览器以外的 JavaScript 定义一个生态系统。webpack 支持以下 CommonJS 方法:
require(dependency: String);
同步地从另一个模块获取导出。编译器将确保依赖项在输出 bundle 中可用。
var $ = require('jquery');
var myModule = require('my-module');
也可以为 `require` 启用魔法注释,请参阅 `module.parser.javascript.commonjsMagicComments` 获取更多信息。
require.resolve(dependency: String);
同步获取模块的 ID。编译器将确保依赖项在输出 bundle 中可用。建议将其视为一个不透明的值,只能与 `require.cache[id]` 或 `__webpack_require__(id)` 一起使用(最好避免这种用法)。
请参阅 `module.id` 获取更多信息。
多次 require 同一个模块只会导致一次模块执行和一次导出。因此,运行时中存在一个缓存。从该缓存中移除值会导致新的模块执行和新的导出。
var d1 = require('dependency');
require('dependency') === d1;
delete require.cache[require.resolve('dependency')];
require('dependency') !== d1;
// in file.js
require.cache[module.id] === module;
require('./file.js') === module.exports;
delete require.cache[module.id];
require.cache[module.id] === undefined;
require('./file.js') !== module.exports; // in theory; in praxis this causes a stack overflow
require.cache[module.id] !== module;
require.ensure(
dependencies: String[],
callback: function(require),
errorCallback: function(error),
chunkName: String
)
将给定的 `dependencies` 分割成一个单独的 bundle,该 bundle 将异步加载。当使用 CommonJS 模块语法时,这是动态加载依赖项的唯一方法。这意味着,此代码可以在执行期间运行,仅当满足特定条件时才加载 `dependencies`。
var a = require('normal-dep');
if (module.hot) {
require.ensure(['b'], function (require) {
var c = require('c');
// Do something special...
});
}
按上述顺序支持以下参数:
异步模块定义(AMD)是一个 JavaScript 规范,它定义了编写和加载模块的接口。webpack 支持以下 AMD 方法:
define([name: String], [dependencies: String[]], factoryMethod: function(...))
如果提供了 `dependencies`,`factoryMethod` 将会以每个依赖项的导出(按相同顺序)被调用。如果没有提供 `dependencies`,`factoryMethod` 将以 `require`、`exports` 和 `module` 被调用(为了兼容性!)。如果此函数返回一个值,则该值由模块导出。编译器确保每个依赖项都可用。
define(['jquery', 'my-module'], function ($, myModule) {
// Do something with $ and myModule...
// Export a function
return function doSomething() {
// ...
};
});
define(value: !Function)
这将导出提供的值。这里的值可以是除函数以外的任何东西。
define({
answer: 42,
});
require(dependencies: String[], [callback: function(...)])
类似于 `require.ensure`,这会将给定的 `dependencies` 分割成一个单独的 bundle,该 bundle 将异步加载。`callback` 将会以 `dependencies` 数组中每个依赖项的导出被调用。
require(['b'], function (b) {
var c = require('c');
});
内部的 `LabeledModulesPlugin` 允许你在模块中使用以下导出和 require 方法:
导出给定的 `value`。标签可以出现在函数声明或变量声明之前。函数名或变量名是导出值所用的标识符。
export: var answer = 42;
export: function method(value) {
// Do something...
};
使依赖项的所有导出在当前作用域中可用。`require` 标签可以出现在字符串之前。该依赖项必须通过 `export` 标签导出值。不能消费 CommonJS 或 AMD 模块。
some-dependency.js
export: var answer = 42;
export: function method(value) {
// Do something...
};
require: 'some-dependency';
console.log(answer);
method(...);
除了上面描述的模块语法外,webpack 还允许一些自定义的、webpack 特有的方法:
require.context(
(directory: String),
(includeSubdirs: Boolean) /* optional, default true */,
(filter: RegExp) /* optional, default /^\.\/.*$/, any file */,
(mode: String) /* optional, 'sync' | 'eager' | 'weak' | 'lazy' | 'lazy-once', default 'sync' */
);
通过指定 `directory` 的路径、`includeSubdirs` 选项、用于更精细控制所包含模块的 `filter` 以及定义加载方式的 `mode`,来指定一整组依赖项。底层模块稍后可以被解析。
var context = require.context('components', true, /\.html$/);
var componentA = context.resolve('componentA');
如果 `mode` 设置为 `'lazy'`,则底层模块将异步加载。
var context = require.context('locales', true, /\.json$/, 'lazy');
context('localeA').then((locale) => {
// do something with locale
});
可用模式及其行为的完整列表在 `import()` 文档中描述。
require.include((dependency: String));
包含一个 `dependency` 但不执行它。这可用于优化模块在输出 chunk 中的位置。
require.include('a');
require.ensure(['a', 'b'], function (require) {
/* ... */
});
require.ensure(['a', 'c'], function (require) {
/* ... */
});
这将产生以下输出:
如果没有 `require.include('a')`,它将在两个匿名 chunk 中重复。
类似于 `require.resolve`,但它不会将 `module` 拉入 bundle。这被认为是一种“弱”依赖。
if (__webpack_modules__[require.resolveWeak('module')]) {
// Do something when module is available...
}
if (require.cache[require.resolveWeak('module')]) {
// Do something when module was loaded before...
}
// You can perform dynamic resolves ("context")
// similarly to other require/import methods.
const page = 'Foo';
__webpack_modules__[require.resolveWeak(`./page/${page}`)];
如果模块源包含无法静态分析的 require,则会发出关键依赖项警告。
示例代码
someFn(require);
require.bind(null);
require(variable);