1.作用
- webpack 是一个静态模块打包器(module bundler)。它会递归地构建一个依赖关系图(dependency graph), 其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle
- 打包:可以把多个Javascript文件打包成一个文件,减少服务器压力和下载带宽。
- 转换:把拓展语言(SCSS/ES6)转换成为普通的JavaScript,让浏览器顺利运行。
- 优化:WebPack具有优化和提升性能的责任。
2.核心概念
- entry:webpack.config.js中配置entry属性定义入口,入口获取依赖模块
- output:webpack.config.js中配置output属性定义输出所创建的bundles
- loader:webpack.config.js中配置module.rules属性中的目标,将非JavaScript文件转化为能够处理的有效模块并进行打包处理
- test:标识应该转换的文件
- use:标识使用的loader
- plugins:
- 插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量,webpack.config.js中配置plugins属性
- 多数插件可通过option自定义,也可针对不同目的传入new实例调用require进来的插件
- mode:通过选择development或production之中的一个,来设置mode参数启用相应模式下的 webpack 内置的优化
3.入口起点
- 单入口:entry: string|Array,若是数组则多个依赖注入到一个chunk中
- 多入口:entry: {[entryChunkName: string]: string|Array}
- 单页面应用:分离应用程序和第三方库入口,应用程序中引用第三方库的部分替换为_ webpack_require _()调用
- 多页面应用:为不同页面创建html文档,复用入口之间的代码/模块
4.输出
- 存在多个入口起点,但只指定一个输出配置
- 最低要求:配置成一个对象
- filename:输出文件文件名
- path:输出目录的绝对路径
- 多个入口起点:使用占位符确保每个文件具有唯一名称filename: ‘[name].js’
- 高级进阶:
- 使用CDN:定义publicPath属性设置CDN地址
- 资源hash:路径末尾写入[hash]
5.loader
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
include: [resolve('src')],
use: 'Happypack/loader?id=js'
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
esModule: false,
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
}
]
}
- 使用loader的三种方式
- 配置:webpack.config.js 文件中指定 loader
- 内联:每个import语句中显示指定loader
- CLI:在shell命令中指定它们
- loader特性
- loader 支持链式传递。能够对资源使用流水线(pipeline)。一组链式的 loader 将按照相反的顺序执行。loader 链中的第一个 loader 返回值给下一个 loader。在最后一个 loader,返回 webpack 所预期的 JavaScript。
- loader 可以是同步的,也可以是异步的。
- loader 运行在 Node.js 中,并且能够执行任何可能的操作。
- loader 接收查询参数。用于对 loader 传递配置。
- loader 也能够使用 options 对象进行配置。
- 除了使用 package.json 常见的 main 属性,还可以将普通的 npm 模块导出为 loader,做法是在 package.json 里定义一个 loader 字段。
- 插件(plugin)可以为 loader 带来更多特性。
- loader 能够产生额外的任意文件。
- 典型loader
- 加载CSS:style-loader和css-loader,含有CSS字符串的< style >插入到html文件的< head >中
- 加载图片:file-loader,图像被处理添加到output目录中,将原有相对路径替换成output目录中图像的最终路径
- 加载字体:file-loader
- 加载数据:JSON文件内置支持,CSV、TSV和XML需要使用 csv-loader 和 xml-loader
6.插件
plugins: [
new HtmlWebpackPlugin({
excludeChunks: ['ui-preview'],
template: './src/main/index.ejs',
filename: './index.html',
favicon: './public/favicon/favicon.ico',
title: version.CONFIG_VERSION_NAME,
inject: false,
hash: true,
mode: devMode //是否是调试模式 'development'
})
]
- 插件HtmlWebpackPlugin:生成新的index.html,内部引入全部生成的bundle文件,将新生成的index.html替换旧的index.html
- 插件CleanWebpackPlugin:构建前清空dist文件夹中内容,仅存在新构建的文件
7.模块解析
resolve: {
extensions: ['.js', '.json', '.vue'],
modules: [
resolve('src'),
resolve('node_modules')
],
alias: {
'@': path.resolve(__dirname, "../src"),
}
}
- 三种文件路径解析
- 绝对路径:不需要解析
- 相对路径:当前目录为上下文目录
- 模块路径:
import "module"
将在resolve选项中进行搜索
- extensions:路径指向文件不具备扩展名时作为文件扩展名
- modules:模块路径解析中在指定目录中查找模块路径
- alias:module设置别名,根据别名路径查找模块
- 路径指向文件夹,采取以下步骤找到正确文件:
- 文件夹包含package.json:resolve.mainFields配置选项中指定的字段匹配package.json 中的第一个这样的字段确定文件路径。
- 文件夹不包含package.json / package.json中的main字段没有返回有效路径: resolve.mainFiles配置选项中指定的文件名匹配 import/require 目录下的文件名。
- 文件扩展名通过 resolve.extensions 选项采用类似的方法进行解析。
- Loader解析遵循与文件解析器指定的规则相同的规则。但是resolveLoader配置选项可以用来为Loader提供独立的解析规则
8.manifest
- runtime :在模块交互时,连接模块所需的加载和解析逻辑。包括浏览器中的已加载模块的连接,以及懒加载模块的执行逻辑。
- Manifest:当编译器(compiler)开始执行、解析和映射应用程序时,它会保留所有模块的详细要点形成的数据结构
- 通过使用 manifest 中的数据,runtime 将能够查询模块标识符,检索出背后对应的模块
9.模块热替换
- 作用:HMR会在应用程序运行过程中替换、添加或删除模块,而无需重新加载整个页面
- 支持:不同文件的loader内置支持HMR
- 方式:保留在完全重新加载页面时丢失的应用程序状态,只更新变更内容
- 步骤:
- 应用程序代码要求 HMR runtime 检查更新。
- HMR runtime(异步)下载更新,然后通知应用程序代码。
- 应用程序代码要求 HMR runtime 应用更新。
- HMR runtime(同步)应用更新
- 编译器update:
- 更新后的 manifest(JSON)
- 一个或多个更新后的 chunk (JavaScript)
- HMR:
- 可选功能:只影响包含HMR代码的模块,描述模块更新后行为
- 更新冒泡:模块没有HMR处理函数情况下更新冒泡,一个处理函数能够对整个模块树进行更新
- 启用HMR:
- 配置devServer:
+ hot: true
- 配置plugins:
+ new webpack.HotModuleReplacementPlugin()
- 修改index.html:
+ if (module.hot) { module.hot.accept('', function() {} ) }
- 通过Node.js API:
const webpackDevServer = require('webpack-dev-server');
const webpack = require('webpack');
const config = require('./webpack.config.js');
const options = {
contentBase: './dist',
hot: true,
host: 'localhost'
};
webpackDevServer.addDevServerEntrypoints(config, options);
const compiler = webpack(config);
const server = new webpackDevServer(compiler, options);
server.listen(5000, 'localhost', () => {
console.log('dev server listening on port 5000');
});