- webpack概述
- 入口起点(Entry Points)
- 输出(Output)
- 模块(Mode)
- 加载器(Loaders)
- 插件(Plugins)
- 配置(Configuration)
- 模块(Modules)
- 模块解析(Module Resolution)
- 依赖图表(Dependency Graph)
- 文件清单(Manifest)
- 构建目标(Targets)
- 模块热替换(Hot Module Replacement)
- 第二部分:配置
- 使用不同语言进行配置(Configuration Languages)
- 多种配置类型
- 入口和上下文(Entry and Context)
- 输出(Output)
- 模块(Module)
- 解析(Resolve)
- 插件(Plugins)
- 开发中 Server(DevServer)
- 开发工具(Devtool)
- 构建目标(Targets)
- Watch 和 WatchOptions
- 外部扩展(Externals)
- 性能(Performance)
- Node
- 统计(Stats)
- 其它选项(Other Options)
- 第三部分:API
- 命令行接口(CLI)
- 包含统计数据的文件(stats data)
- Node.js API
- 模块热替换(Hot Module Replacement)
- 加载器 API
- 模块方法(module methods)
- 模块变量(module variables)
- Plugin API
- compiler 钩子
- compilation 钩子
- resolver
- parser
- 第四部分:指南
- 安装
- 起步
- 管理资源
- 管理输出
- 开发
- 模块热替换
- Tree shaking
- 生产环境构建
- 代码拆分(Code Splitting)
- 懒加载(Lazy Loading)
- 缓存(Caching)
- 创建库 (Library)
- Shimming
- 渐进式网络应用程序
- TypeScript
- 迁移到新版本
- 使用环境变量
- 构建性能
- 内容安全策略
- 开发 - Vagrant
- 管理依赖
- Public Path(公共路径)
- 集成(Integrations)
- 第五部分:加载器
- babel-loader
- yaml-frontmatter-loader
- cache-loader
- coffee-loader
- coffee-redux-loader
- coverjs-loader
- css-loader
- exports-loader
- expose-loader
- extract-loader
- file-loader
- gzip-loader
- html-loader
- i18n-loader
- imports-loader
- istanbul-instrumenter-loader
- jshint-loader
- json-loader
- json5-loader
- less-loader
- bundle-loader
- multi-loader
- node-loader
- null-loader
- polymer-webpack-loader
- postcss-loader
- raw-loader
- react-proxy-loader
- restyle-loader
- sass-loader
- script-loader
- source-map-loader
- style-loader
- svg-inline-loader
- thread-loader
- transform-loader
- url-loader
- val-loader
- worker-loader
- mocha-loader
- 第六部分:插件
- AggressiveSplittingPlugin
- ZopfliWebpackPlugin
- BannerPlugin
- ClosureWebpackPlugin
- CommonsChunkPlugin
- ComponentWebpackPlugin
- CompressionWebpackPlugin
- ContextReplacementPlugin
- CopyWebpackPlugin
- DefinePlugin
- DllPlugin
- EnvironmentPlugin
- EvalSourceMapDevToolPlugin
- ExtractTextWebpackPlugin
- HashedModuleIdsPlugin
- HotModuleReplacementPlugin
- HtmlWebpackPlugin
- BabelMinifyWebpackPlugin
- IgnorePlugin
- LoaderOptionsPlugin
- MinChunkSizePlugin
- ModuleConcatenationPlugin
- NamedModulesPlugin
- NormalModuleReplacementPlugin
- NpmInstallWebpackPlugin
- PrefetchPlugin
- ProfilingPlugin
- ProvidePlugin
- SourceMapDevToolPlugin
- SplitChunksPlugin
- UglifyjsWebpackPlugin
- WatchIgnorePlugin
- I18nWebpackPlugin
创建库 (Library)
除了打包应用程序代码,webpack 还可以用于打包 JavaScript library。以下指南适用于希望流水线化(streamline)打包策略的 library 作者。
创建一个 library
假设你正在编写一个名为 webpack-numbers
的小的 library,可以将数字 1 到 5 转换为文本表示,反之亦然,例如将 2 转换为 'two'。
基本的项目结构可能如下所示:
project
+ |- webpack.config.js
+ |- package.json
+ |- /src
+ |- index.js
+ |- ref.json
初始化 npm,安装 webpack 和 lodash:
npm init -y
npm install --save-dev webpack lodash
src/ref.json
[{
"num": 1,
"word": "One"
}, {
"num": 2,
"word": "Two"
}, {
"num": 3,
"word": "Three"
}, {
"num": 4,
"word": "Four"
}, {
"num": 5,
"word": "Five"
}, {
"num": 0,
"word": "Zero"
}]
src/index.js
import _ from 'lodash';
import numRef from './ref.json';
export function numToWord(num) {
return _.reduce(numRef, (accum, ref) => {
return ref.num === num ? ref.word : accum;
}, '');
};
export function wordToNum(word) {
return _.reduce(numRef, (accum, ref) => {
return ref.word === word && word.toLowerCase() ? ref.num : accum;
}, -1);
};
该 library 的使用方式如下:
// ES2015 模块引入
import * as webpackNumbers from 'webpack-numbers';
// CommonJS 模块引入
var webpackNumbers = require('webpack-numbers');
// ...
// ES2015 和 CommonJS 模块调用
webpackNumbers.wordToNum('Two');
// ...
// AMD 模块引入
require(['webpackNumbers'], function ( webpackNumbers) {
// ...
// AMD 模块调用
webpackNumbers.wordToNum('Two');
// ...
});
用户还可以通过 script 标签来加载和使用此 library:
<!doctype html>
<html>
...
<script src="https://unpkg.com/webpack-numbers"></script>
<script>
// ...
// 全局变量
webpackNumbers.wordToNum('Five')
// window 对象中的属性
window.webpackNumbers.wordToNum('Five')
// ...
</script>
</html>
注意,我们还可以通过以下配置方式,将 library 暴露:
- global 对象中的属性,用于 Node.js。
this
对象中的属性。
完整的 library 配置和相关代码请参阅 webpack library 示例。
基本配置
现在,让我们以某种方式打包这个 library,能够实现以下几个目标:
- 不打包
lodash
,而是使用externals
来 require 用户加载好的 lodash。 - 设置 library 的名称为
webpack-numbers
. - 将 library 暴露为一个名为
webpackNumbers
的变量。 - 能够访问其他 Node.js 中的 library。
此外,用户应该能够通过以下方式访问 library:
- ES2015 模块。例如
import webpackNumbers from 'webpack-numbers'
。 - CommonJS 模块。例如
require('webpack-numbers')
. - 全局变量,当通过
script
脚本引入时
我们可以从这个基本的 webpack 配置开始:
webpack.config.js
var path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack-numbers.js'
}
};
外部化 lodash
现在,如果执行 webpack
,你会发现创建了一个非常巨大的文件。如果你查看这个文件,会看到 lodash 也被打包到代码中。在这种场景中,我们更倾向于把 lodash
当作 peerDependency
。也就是说,用户应该已经将 lodash
安装好。因此,你可以放弃对外部 library 的控制,而是将控制权让给使用 library 的用户。
这可以使用 externals
配置来完成:
webpack.config.js
var path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack-numbers.js'
- }
+ },
+ externals: {
+ lodash: {
+ commonjs: 'lodash',
+ commonjs2: 'lodash',
+ amd: 'lodash',
+ root: '_'
+ }
+ }
};
这意味着你的 library 需要一个名为 lodash
的依赖,这个依赖在用户的环境中必须存在且可用。
T> 注意,如果你计划只是将 library 用作另一个 webpack bundle 中的依赖模块,则可以将 externals
指定为数组。
外部扩展的限制
对于从一个依赖目录中,调用多个文件的 library:
import A from 'library/one';
import B from 'library/two';
// ...
无法通过在 externals 中指定 library
目录的方式,将它们从 bundle 中排除。你需要逐个排除它们,或者使用正则表达式排除。
externals: [
'library/one',
'library/two',
// Everything that starts with "library/"
/^library\/.+$/
]
暴露 library
对于用途广泛的 library,我们希望它能够兼容不同的环境,例如 CommonJS,AMD,Node.js 或者作为一个全局变量。为了让你的 library 能够在各种用户环境(consumption)中可用,需要在 output
中添加 library
属性:
webpack.config.js
var path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
- filename: 'webpack-numbers.js'
+ filename: 'webpack-numbers.js',
+ library: 'webpackNumbers'
},
externals: {
lodash: {
commonjs: 'lodash',
commonjs2: 'lodash',
amd: 'lodash',
root: '_'
}
}
};
T> 注意,library
设置绑定到 entry
配置。对于大多数库,指定一个入口起点就足够了。虽然构建多个库也是也可以的,然而还可以直接通过将主入口脚本(index script)暴露部分导出,来作为单个入口起点则相对简单。不推荐使用数组
作为库的 entry
。
当你在 import 引入模块时,这可以将你的 library bundle 暴露为名为 webpackNumbers
的全局变量。为了让 library 和其他环境兼容,还需要在配置文件中添加 libraryTarget
属性。这是可以控制 library 如何以不同方式暴露的选项。
webpack.config.js
var path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack-numbers.js',
- library: 'webpackNumbers'
+ library: 'webpackNumbers',
+ libraryTarget: 'umd'
},
externals: {
lodash: {
commonjs: 'lodash',
commonjs2: 'lodash',
amd: 'lodash',
root: '_'
}
}
};
可以通过以下方式暴露 library:
- 遍历:作为一个全局变量,通过
script
标签来访问(libraryTarget:'var'
)。 - this:通过
this
对象访问(libraryTarget:'this'
)。 - window:通过
window
对象访问,在浏览器中(libraryTarget:'window'
)。 - UMD:在 AMD 或 CommonJS 的
require
之后可访问(libraryTarget:'umd'
)。
如果设置了 library
但没设置 libraryTarget
,则 libraryTarget
默认为 var
,详细说明请查看 output 配置文档。查看 output.libraryTarget
,以获取所有可用选项的详细列表。
W> 在 webpack 3.5.5 中,使用 libraryTarget: { root:'_' }
将无法正常工作(参考 issue 4824) 所述)。然而,可以设置 libraryTarget: { var: '_' }
来将 library 作为全局变量。
最终步骤
遵循生产环境指南中的步骤,来优化生产环境下的输出。那么,我们还需要通过设置 package.json
中的 main
字段,添加生成 bundle 的文件路径。
package.json
{
...
"main": "dist/webpack-numbers.js",
...
}
或者,按照这里的指南添加为标准模块:
{
...
"module": "src/index.js",
...
}
键(key) main
是指 package.json
标准,以及 module
是 一个提案,此提案允许 JavaScript 生态系统升级使用 ES2015 模块,而不会破坏向后兼容性。
W> module
属性应指向一个使用 ES2015 模块语法的脚本,但不包括浏览器或 Node.js 尚不支持的其他语法特性。这使得 webpack 本身就可以解析模块语法,如果用户只用到 library 的某些部分,则允许通过 tree shaking 打包更轻量的包。
现在你可以将其发布为一个 npm 包,并且在 unpkg.com 找到它并分发给你的用户。
T> 为了暴露和 library 关联着的样式表,你应该使用 ExtractTextPlugin
。然后,用户可以像使用其他样式表一样使用和加载这些样式表。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论