模块方法 | Module Methods

Module Methods

本节涵盖了使用 webpack 编译代码的所有方法。在 webpack 打包应用程序时,你可以选择各种模块语法风格,包括 ES6, CommonJSAMD

尽管webpack支持多种模块语法,但我们建议遵循一致的语法来避免奇怪的行为/错误。这里有一个混合ES6和CommonJS的例子,但是肯定有其他例子

ES6(推荐)

webpack的第2版原生支持ES6模块语法,这意味着您可以使用importexport不使用像babel这样的工具来为您处理此问题。请记住,您仍然可能需要babel才能使用其他ES6 +功能。webpack支持以下方法:

import

通过 import 以静态的方式,导入另一个通过 export 导出的模块。

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

这里的关键字是静态的。正常import语句不能在其他逻辑中动态使用或包含变量。有关更多信息,请参阅规范,以import()获取动态使用情况。

export

// Named exports export var Count = 5; export function Multiply(a, b) { return a * b; } // Default export export default { // Some data... }

import()

import('path/to/module') -> Promise

动态加载模块。调用import()被视为分割点,这意味着请求的模块和它的子项被分割为一个单独的块。

ES2015 loader 规范 定义了 import() 方法,可以在运行时动态地加载 ES2015 模块。

if ( module.hot ) { import('lodash').then(_ => { // Do something with lodash (a.k.a '_')... }) }

import() 特性依赖于内置的 Promise。如果想在低版本浏览器使用 import(),记得使用像 es6-promise 或者 promise-polyfill 这样 polyfill 库,来预先填充(shim) Promise 环境。。

import( /* webpackChunkName: "my-chunk-name" */ /* webpackMode: "lazy" */ 'module'

webpackMode:由于webpack 2.6.0,可以指定解决动态导入的不同模式。支持以下选项:

  • "lazy"(默认):为每个 import() 导入的模块,生成一个可延迟加载(lazy-loadable) chunk。

  • "lazy-once":生成一个可以满足所有 import() 调用的单个可延迟加载(lazy-loadable) chunk。此 chunk 将在第一次 import() 调用时获取,随后的 import() 调用将使用相同的网络响应。注意,这种模式仅在部分动态语句中有意义,例如 import(`./locales/${language}.json`),其中可能含有多个被请求的模块路径。

  • "eager":不会生成额外的 chunk,所有模块都被当前 chunk 引入,并且没有额外的网络请求。仍然会返回 Promise,但是是 resolved 状态。和静态导入相对比,在调用 import()完成之前,该模块不会被执行。

  • "weak":尝试加载模块,如果该模块函数已经以其他方式加载(即,另一个 chunk 导入过此模块,或包含模块的脚本被加载)。仍然会返回 Promise,但是只有在客户端上已经有该 chunk 时才成功解析。如果该模块不可用,Promise 将会是 rejected 状态,并且网络请求永远不会执行。当需要的 chunks 始终在(嵌入在页面中的)初始请求中手动提供,而不是在应用程序导航在最初没有提供的模块导入的情况触发,这对于通用渲染(SSR)是非常有用的。

CommonJS

require

require(dependency: String)

以同步的方式检索其他模块的导出。由编译器(compiler)来确保依赖项在最终输出 bundle 中可用。

var $ = require("jquery" var myModule = require("my-module"

异步使用它可能没有预期的效果。

require.resolve

require.resolve(dependency: String)

webpack 中模块 ID 是一个数字(而在 NodeJS 中是一个字符串 -- 也就是文件名)。

require.cache

多处引用同一个模块,最终只会产生一次模块执行和一次导出。所以,会在运行时(runtime)中会保存一份缓存。删除此缓存,会产生新的模块执行和新的导出。

只有在极少数情况下才需要兼容性!

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

require.ensure()特定于webpack并被替代import()

require.ensure(dependencies: String[], callback: function(require), errorCallback: function(error), chunkName: String)

这个特性依赖于内置的 Promise。如果想在低版本浏览器使用 require.ensure,记得使用像 es6-promise 或者 promise-polyfill 这样 polyfill 库,来预先填充(shim) Promise 环境。

var a = require('normal-dep' if ( module.hot ) { require.ensure(['b'], function(require) { var c = require('c' // Do something special... } }

以上参数按以上指定的顺序支持:

  • dependencies:一个字符串数组,用于声明callback要执行的代码所需的所有模块。

  • callback:只要加载好全部依赖,webpack 就会执行此函数。require 函数的实现,作为参数传入此函数。当程序运行需要依赖时,可以使用 require() 来加载依赖。函数体可以使用此参数,来进一步执行 require() 模块。

  • errorCallback:当webpack无法加载依赖关系时执行的函数。

  • chunkName:由 require.ensure() 创建出的 chunk 的名字。通过将同一个 chunkName 传递给不同的 require.ensure() 调用,我们可以将它们的代码合并到一个单独的 chunk 中,从而只产生一个浏览器必须加载的 bundle。

虽然我们将 require 的实现,作为参数传递给回调函数,然而如果使用随意的名字,例如 require.ensure([], function(request) { request('someModule' }) 则无法被 webpack 静态解析器处理,所以还是请使用 require,例如 require.ensure([], function(require) { require('someModule' })。

AMD

AMD(Asynchronous Module Definition) 是一种定义了写入模块接口和加载模块接口的 JavaScript 规范。webpack 支持以下的 AMD 方法:

define (with factory)

define([name: String], [dependencies: String[]], factoryMethod: function(...))

请注意,webpack会忽略name参数。

define(['jquery', 'my-module'], function($, myModule) { // Do something with $ and myModule... // Export a function return function doSomething() { // ... }; }

这不能用于异步功能。

define (with value)

define(value: !Function)

只会将提供的 value 导出。这里的 value 可以是除函数外的任何值。

define{ answer: 42 }

这不能用于异步功能。

require (AMD-版)

require(dependencies: String[], [callback: function(...)])

require.ensure 类似,给定 dependencies 参数,将其对应的文件拆分到一个单独的 bundle 中,此 bundle 会被异步加载。然后会调用 callback 回调函数,并传入 dependencies 数组中每一项的导出。

这个特性依赖于内置的 Promise。如果想在低版本浏览器使用 require.ensure,记得使用像 es6-promise 或者 promise-polyfill 这样 polyfill 库,来预先填充(shim) Promise 环境。

require(['b'], function(b) { var c = require("c" }

没有选项可以提供块名称。

标签模块

webpack 内置的 LabeledModulesPlugin 插件,允许使用下面的方法导出和导入模块:

export 标签

导出给定的 valueexport 标记可以出现在函数声明或变量声明之前。函数名或变量名是导出值的标识符。

export: var answer = 42; export: function method(value) { // Do something... };

在异步函数中使用它可能没有预期的效果。

require 标签

some-dependency.js

export: var answer = 42; export: function method(value) { // Do something... };

require: 'some-dependency'; console.log(answer method(...

WebPack

除了上述模块语法之外,webpack还允许一些定制的,特定于webpack的方法:

require.context

require.context(directory:String, includeSubdirs:Boolean /* optional, default true */, filter:RegExp /* optional */)

var context = require.context('components', true, /\.html$/ var componentA = context.resolve('componentA'

require.include

require.include(dependency: String)

require.include('a' require.ensure(['a', 'b'], function(require) { /* ... */ } require.ensure(['a', 'c'], function(require) { /* ... */ }

这将导致以下输出:

  • 输入块:file.jsa

  • 匿名块: b

  • 匿名块: c

require.resolveWeak

require.resolve此类似,但这不会拉module入包中。这就是所谓的“弱”依赖。

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") // just as with other require/import methods. const page = 'Foo'; __webpack_modules__[require.resolveWeak(`./page/${page}`)]

require.resolveWeak通用渲染(SSR +代码分割)的基础,正如在诸如react-universal-component之类的软件包中使用的那样。它允许代码在服务器和客户端上的初始页面加载中同步呈现。它要求大块手动服务或以某种方式可用。它能够在不需要指示它们应该被捆绑成块的情况下需要模块。import()当用户导航触发额外的导入时,它将与其一起使用。