Webpack 是当下最热门的前端资源模块化管理和打包工具。它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分隔,等到实际需要的时候再异步加载。通过 loader 的转换,任何形式的资源都可以视作模块,比如 CommonJs 模块、 AMD 模块、 ES6 模块、CSS、图片、 JSON、Coffeescript、 LESS 等。总的来说webpack可以对模块进行压缩、预处理、按需打包、按需加载等。
webpack 有哪些重要特征?
- 插件化:webpack本身非常灵活,提供了丰富的插件接口。基于这些接口,webpack开发了很多插件作为内置功能。
- 速度快:webpack使用异步IO以及多级缓存机制。所以webpack的速度是很快的,尤其是增量更新。
- 高适配性:webpack同时支持AMD/CommonJs/ES6模块方案。webpack会静态解析你的代码,自动帮你管理他们的依赖关系。此外,webpack对第三方库的兼容性很好。
- 代码拆分:webpack可以将你的代码分片,从而实现按需打包。这种机制可以保证页面只加载需要的JS代码,减少首次请求的时间。
- 优化:webpack提供了很多优化机制来减少打包输出的文件大小,不仅如此,它还提供了hash机制,来解决浏览器缓存问题。
- 开发模式友好:webpack为开发模式也提供了很多辅助功能。比如SourceMap、热更新等。
- 使用场景多:webpack不仅适用于web应用场景,也适用于Webworkers、Node.js场景
github地址:https://github.com/San-Shui/webpack-demo
webpack-demo是通过学习webpack官网的知识,编写一个webpack服务demo,以下是webpack.config.js配置:
const path = require('path')
// 生成一个HTML5文件
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 清理文件夹
const CleanWebpackPlugin = require('clean-webpack-plugin')
// 将内容束展示为方便交互的直观树状图
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// 引入webpack
const webpack = require('webpack')
// 高性能的webpack uglify plugin
const FastUglifyJsPlugin = require('fast-uglifyjs-plugin')
/* 处理路径
path.join([path1][, path2][, ...])
用于连接路径。该方法的主要用途在于,会正确使用当前系统的路径分隔符,Unix系统是/,Windows系统是\。
path.resolve([from ...], to)
将 to 参数解析为绝对路径。
*/
function resolve (dir) {
return path.join(__dirname, dir)
}
module.exports = {
/*每个 HTML 页面都有一个入口起点。单页应用(SPA):一个入口起点,多页应用(MPA):多个入口起点。
如果传入一个字符串或字符串数组,chunk 会被命名为 main。
如果传入一个对象,则每个键(key)会是 chunk 的名称,该值描述了 chunk 的入口起点。
*/
entry: {
app: path.resolve(__dirname, 'src', 'index.js'), // 使用path.resolve解析为绝对路径
another: resolve('src/another-module.js') // 使用path.join连接路径
},
/* 指示 webpack 如何去输出、以及在哪里输出你的「bundle、asset 和其他你所打包或使用 webpack 载入的任何内容」。
*/
output: {
/*filename:此选项不会影响那些「按需加载 chunk」的输出文件。对于这些文件,请使用 output.chunkFilename
选项来控制输出。
[hash] 模块标识符(module identifier)的 hash
[chunkhash] chunk 内容的 hash
[name] 模块名称
[id] 模块标识符(module identifier)
*/
filename: '[name].[hash].js',
/* 在编写一个导出值的 JavaScript library 时,可以使用下面的 library 和 libraryTarget,
导出值可以作为其他代码的依赖。
*/
library: "MyLibrary",
/* 配置如何暴露 library
"var" - (默认值)当 library 加载完成,入口起点的返回值将分配给一个变量
"this" - 当 library 加载完成,入口起点的返回值将分配给 this
"window" - 当 library 加载完成,入口起点的返回值将分配给 window 对象。
"global" - 当 library 加载完成,入口起点的返回值将分配给 global 对象。
"commonjs" - 当 library 加载完成,入口起点的返回值将分配给 exports 对象。
"commonjs2" - 当 library 加载完成,入口起点的返回值将分配给 exports 对象
"amd" - webpack 将你的 library 转为 AMD 模块
libraryTarget: "umd" - 这是一种可以将你的 library 能够在所有的模块定义下都可运行的方式
(并且导出的完全不是模块)。
*/
libraryTarget: "var",
/* 目录对应一个绝对路径
*/
path: resolve('dist'),
/* 散列摘要的前缀长度,默认为 20
*/
hashDigestLength: 24,
/* 告诉 webpack 在 bundle 中引入「所包含模块信息」的相关注释。此选项默认值是 false
*/
pathinfo: true,
/* 按需加载chunk的输出文件
*/
chunkFilename:'js/[name].js',
/* 按需加载(on-demand-load)或加载外部资源(external resources)(如图片、文件等)
publicPath: "https://cdn.example.com/assets/", // CDN(总是 HTTPS 协议)
publicPath: "//cdn.example.com/assets/", // CDN (协议相同)
publicPath: "/assets/", // 相对于服务(server-relative)
publicPath: "assets/", // 相对于 HTML 页面
publicPath: "../assets/", // 相对于 HTML 页面
*/
publicPath: "", // 相对于 HTML 页面(目录相同)
},
/* externals 配置选项提供了「从输出的 bundle 中排除依赖」的方法
*/
externals: {
'lodash': {
commonjs: 'lodash',
commonjs2: 'lodash',
amd: 'lodash',
root: '_'
}
},
/* 开发工具(Devtool)此选项控制是否生成,以及如何生成 source map
*/
devtool: 'inline-source-map', // inline-source-map - SourceMap 转换为 DataUrl 后添加到 bundle 中。
/* 如果你通过 Node.js API 来使用 dev-server, devServer 中的选项将被忽略。
将选项作为第二个参数传入: new WebpackDevServer(compiler, {...})
*/
devServer: {
contentBase: resolve("dist"), // 在 localhost:8080 下建立服务,将 dist 目录下的文件,作为可访问文件。
hot: true, // 启用 webpack 的模块热替换特性
compress: true, // 一切服务都启用gzip 压缩
// color: true, // 启用/禁用控制台上的颜色
// host: '0.0.0.0', // 默认是 localhost
port: 9000 // 指定要监听请求的端口号
// openPage: '/different/page' //指定打开浏览器时要导航的页面
// overlay: true //当有编译器错误或警告时,在浏览器中显示全屏覆盖。默认禁用。如果您只想显示编译器错误:
},
/* 解析(Resolve):这些选项能设置模块如何被解析
*/
resolve: {
/* 告诉 webpack 解析模块时应该搜索的目录。下面配置src目录优先于 node_modules搜索
*/
modules: [
resolve('src'),
resolve('node_modules')
],
/* 创建 import 或 require 的别名,来确保模块引入变得更简单。
*/
alias: {
jquery: "jquery/src/jquery",
Utilities: resolve('src/utilities/'),
Templates: resolve('src/templates/'),
xyz$: resolve('path/to/file.js'), // 在给定对象的键后的末尾添加 $,以表示精准匹配
},
/* 自动解析确定的扩展。默认值为:extensions: [".js", ".json"]
*/
extensions: ['.js', '.vue', '.json']
},
/* module选项决定了如何处理项目中的不同类型的模块
*/
module: {
/* rules创建模块时,匹配请求的规则数组。这些规则能够修改模块的创建方式。
*/
rules: [
/* 加载 js
*/
{
test: /\.js$/,
loader: 'babel-loader?cacheDirectory=true',
include: [resolve('src'), resolve('test')],
exclude: /node_modules/ // 不能满足的条件(排除不处理的目录)
},
/* 加载 CSS
*/
{
test: /\.css$/,
loader: ['style-loader', 'css-loader'],
include: resolve('src'),
exclude: /node_modules/ // 不能满足的条件(排除不处理的目录)
},
/* 加载 sass 和 less
*/
{
test: /\.scss$/,
loader: ['style-loader', 'css-loader', 'sass-loader'],
include: resolve('src'),
exclude: /node_modules/ // 不能满足的条件(排除不处理的目录)
},
/* 加载 图片
*/
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
/* loader: ['file-loader'], // file-loader主要用来处理图片,其实也可以在js和html及其他文件上,但很少那么使用.
*/
loader: 'url-loader', // url-loader 功能类似于 file-loader,但是在文件大小(单位 byte)低于指定的限制时,可以返回一个 DataURL。
options: {
limit: 10000 // 小于10K的图片转成base64编码的DataURL字符串写到代码中
},
include: resolve('src'),
exclude: /node_modules/ // 不能满足的条件(排除不处理的目录)
},
/* 加载 字体
*/
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000
},
include: resolve('src'),
exclude: /node_modules/, // 不能满足的条件(排除不处理的目录)
},
/* 加载 CSV、TSV
*/
{
test: /\.(csv|tsv)$/,
loader: 'csv-loader',
include: resolve('src'),
exclude: /node_modules/ // 不能满足的条件(排除不处理的目录)
},
/* 加载 xml
*/
{
test: /\.xml$/,
loader: 'xml-loader',
include: resolve('src'),
exclude: /node_modules/ // 不能满足的条件(排除不处理的目录)
}
]
},
/* 插件列表
*/
plugins: [
/* 清理 /dist 文件夹
*/
new CleanWebpackPlugin(['dist']),
/* 设定 HtmlWebpackPlugin,然而 HtmlWebpackPlugin 还是会默认生成 index.html 文件
*/
new HtmlWebpackPlugin({
template: resolve('src/index.html')
// title: 'Caching'
}),
/* 启用 HMR
*/
new webpack.HotModuleReplacementPlugin(),
/* JS文件压缩
*/
new webpack.optimize.UglifyJsPlugin({
sourceMap: 'inline-source-map',
compress: {
warnings: false,
// 移除掉代码中的 console
drop_console: true,
pure_funcs: ['console.log']
}
}),
/* Node 环境变量
*/
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
/* 防止重复:使用 CommonsChunkPlugin 去重和分离 chunk。
*/
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor', // Specify the common bundle's name.
filename: 'vendor-[hash].min.js',
}),
/* ProvidePlugin 可以将模块作为一个变量,被 webpack 在其他每个模块中引用。
只有你需要使用此变量的时候,这个模块才会被 require 进来。
*/
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}),
/* 能以可视化的方式展示打包结果,为你提供分析需求
*/
new BundleAnalyzerPlugin(),
/* Scope Hoisting译作“作用域提升”。只需在配置文件中添加一个新的插件,就可以让 Webpack
打包出来的代码文件更小、运行的更快(实际上没有任何影响,体积大小没变)
*/
new webpack.optimize.ModuleConcatenationPlugin(),
/* 增强代码代码压缩,高性能的webpack uglify plugin
*/
new FastUglifyJsPlugin({
compress: {
warnings: false
},
// debug设为true可输出详细缓存使用信息:
debug: true,
// 默认开启缓存,提高uglify效率,关闭请使用:
cache: true,
// 默认缓存路径为项目根目录,手动配置请使用:
cacheFolder: resolve('.otherFolder'),
// 工作进程数,默认os.cpus().length
workerNum: 2
})
]
};
1、前提条件
在开始之前,请确保安装了 Node.js 的最新版本。使用 Node.js 最新的长期支持版本(LTS - Long Term Support),是理想的起步。使用旧版本,你可能遇到各种问题,因为它们可能缺少 webpack 功能以及/或者缺少相关 package 包。
2、本地安装
要安装最新版本或特定版本,请运行以下命令之一:
npm install --save-dev webpack
3、全局安装
以下的 NPM 安装方式,将使 webpack 在全局环境下可用:
npm install --global webpack
clone远程仓库到本地:
git clone https://github.com/San-Shui/webpack-demo.git
进入webpack-demo目录
cd webpack-demo
安装依赖
yarn install 或者 npm install
运行项目
yarn run start 或者 npm run start