webpack 是一个模块打包机,将根据文件间的依赖关系对其进行静态分析,而后将这些模块按指定规则生成静态资源webpack
当 webpack 处理程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序须要的每一个模块,而后将全部这些模块打包成一个或多个 bundleweb
主要承担以下功能:npm
打包:将多个文件 打包成 一个文件,减小服务器压力和下载带宽编程
转换:将预编译语言 转换成 浏览器识别的语言浏览器
优化:性能优化缓存
webpack 特色:性能优化
代码拆分
webpack 有两种组织模块的依赖方式,同步、异步
异步依赖将做为分割点,造成一个新的块;在优化了依赖树以后,每个异步区块都将做为一个文件被打包
智能解析
webpack 有一个智能解析器,几乎能够处理任何第三方库
不管它们的模块形式是 CommonJS、 AMD 仍是普通的 JS 文件;甚至在加载依赖的时候,容许使用动态表达式 require("./templates/" + name + ".jade")
快速运行
webpack 使用异步 I/O 、多级缓存提升运行效率,使得 webpack 以难以使人置信的速度 快速增量编译
全局安装
sudo npm i webpack -g
复制代码
局部安装
// 在已经 npm 初始化的项目 根目录执行
npm i webpack -D
复制代码
提醒:webpack4.x 版本须要额外安装 webpack-cli
// 如下为局部安装方式,全局安装同上
npm i webpack-cli -D
复制代码
在使用 webpack 构建的典型应用程序或站点中,有三种主要的代码类型:
你或你的团队编写的源码。
你的源码会依赖的任何第三方的 library 或 "vendor" 代码。
webpack 的 runtime 和 manifest,管理全部模块的交互
下面 阐述 runtime
runtime 包含:在模块交互时,链接模块所需的加载和解析逻辑;包括浏览器中的已加载模块的链接,以及懒加载模块的执行逻辑
下面 阐述 manifest
当编译器(compiler)开始执行、解析、映射应用程序时,它会保留全部模块的详细要点,这个数据集合称为 "Manifest"
当完成打包并发送到浏览器时,会在运行时经过 manifest 来解析、加载模块
runtime 和 manifest 管理模块的交互
在浏览器运行时,runtime 和 manifest 用来链接模块化的应用程序的全部代码
不管你选择哪一种模块语法,那些 import 或 require 语句如今都已经转换为
__webpack_require__
方法,此方法指向模块标识符(module identifier)
经过使用 manifest 中的数据(每一个模块的详细要点:映射、依赖等),runtime 将可以查询模块标识符,检索出背后对应的模块
做用
告诉 webpack 从哪一个文件开始构建,这个文件将做为 webpack 依赖关系图的起点
配置 单入口
// webpack 配置
module.exports = {
entry: './path/to/my/entry/file.js'
};
复制代码
// webpack 配置
module.exports = {
entry: {
main: './src/main.js'
}
};
复制代码
配置 多入口
// 场景一:分离 应用程序(app) 和 第三方库(vendor) 入口
// webpack 配置
module.exports = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
};
复制代码
// 场景二:多页面应用程序,告诉 webpack 须要 3 个独立分离的依赖图
// webpack 配置
module.exports = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
};
复制代码
做用
告诉 webpack 在哪里输出 构建后的包、包的名称 等
配置 单出口
// webpack 配置
const path = require('path');
module.exports = {
entry: main: './src/main.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
}
};
复制代码
配置 多出口
// webpack 配置
const path = require('path');
module.exports = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
};
复制代码
其余参数配置
做用
loader 让 webpack 可以去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)
loader 能够将全部类型的文件转换为 webpack 可以处理的有效模块
loader 使用方式:配置(经常使用)
// 安装 loader
npm install --save-dev css-loader
复制代码
// webpack 配置
module.exports = {
module: {
rules: [{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}]
}
};
// 或
module.exports = {
module: {
rules: [{
test: /\.css$/,
use: ['style-loader', {
loader: 'css-loader',
options: {
modules: true
}
}]
}]
}
};
复制代码
loader 使用方式:内联 (不经常使用)
// 在项目文件中,import 语句时使用
import Styles from 'style-loader!css-loader?modules!./styles.css';
复制代码
loader 使用方式:CLI(不经常使用)
webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
// 如上 会对 .jade 文件使用 jade-loader,对 .css 文件使用 style-loader 和 css-loader
复制代码
loader 特性
几乎全部 loader 都 须要安装, 但 不须要 在 webpack 配置文件中经过 require
引入
逆向编译,链式传递
// webpack 配置
module.exports = {
module: {
rules: [{
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader']
}]
}
};
// 如上,css 文件编译顺序依次为:postcss-loader ---> css-loader ---> style-loader
// 编译过程当中,第一个loader的值 传递给下一个loader,依次传递;最后一个loader编译完成后,将预期值传递给 webpack
复制代码
做用
能够处理各类任务,从打包优化和压缩,一直到从新定义环境中的变量
plugin 使用
npm i html-webpack-plugin -D
复制代码
// webpack 配置
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
};
复制代码
plugin 特性
有些插件须要单独安装,有些插件是webpack内置插件 不须要单独安装
但全部的插件都 须要 在 webpack 配置文件中经过
require
引入
plugin 剖析:
webpack 插件是一个具备 apply 属性的 JavaScript 对象
apply 属性会被 webpack compiler 调用,而且 compiler 对象可在整个编译生命周期访问
// ConsoleLogOnBuildWebpackPlugin.js
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
compiler.hooks.run.tap(pluginName, compilation => {
console.log("webpack 构建过程开始!");
});
}
}
复制代码
做用
告诉 webpack 使用相应模式的内置优化
使用
// webpack 配置
module.exports = {
mode: 'production'
};
复制代码
// CLI 参数中
webpack --mode=production
复制代码
两种模式的区别
选项 | 描述 |
---|---|
development |
会将 process.env.NODE_ENV 的值设为 development启用 NamedChunksPlugin 和 NamedModulesPlugin |
production |
会将 process.env.NODE_ENV 的值设为 production。 启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin |
// mode: development
module.exports = {
+ mode: 'development'
- plugins: [
- new webpack.NamedModulesPlugin(),
- new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
- ]
}
复制代码
// mode: production
module.exports = {
+ mode: 'production',
- plugins: [
- new UglifyJsPlugin(/* ... */),
- new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
- new webpack.optimize.ModuleConcatenationPlugin(),
- new webpack.NoEmitOnErrorsPlugin()
- ]
}
复制代码
在 webpack 中区分两种 模式
if(process.env.NODE_ENV === 'development'){
//开发环境 do something
}else{
//生产环境 do something
}
复制代码
webpack 可以为 多种环境 或 target 构建编译(编译后代码 的运行环境)
默认值:
web
常见值 见 API
不一样的 source map(资源映射)
会决定 代码中错误的显示方式(打包后代码、生成后代码、转换过代码、源代码等 详细见)
会影响 构建(build)、从新构建(rebuild) 的速度
整个 source map 做为一个单独的文件生成。它为 bundle 添加了一个引用注释,以便开发工具知道在哪里能够找到它
开发环境的几种常见的 source map
以以下代码为例,运行
console.log('js');
class A extends test {}
复制代码
eval-source-map
构建速度:-- 、从新构建速度:+ 、生产环境:no 、显示原始源代码
cheap-eval-source-map
构建速度:+ 、从新构建速度:++ 、生产环境:no 、转换过的代码(仅限行)
cheap-module-eval-source-map
【推荐】
构建速度:0 、从新构建速度:++ 、生产环境:no 、原始源代码(仅限行)
生产环境中 常见的 source map
以以下代码为例,运行
console.log('js');
class A extends test {}
复制代码
none
【推荐】
构建速度:+++ 、从新构建速度:+++ 、生产环境:yes 、打包后代码
总结: 须要注意的是不一样的 devtool 的设置,会致使不一样的性能差别。
"eval" 具备最好的性能,但并不能帮助你转译代码。
若是你能接受稍差一些的 mapping 质量,可使用 cheap-source-map 选项来提升性能
使用 eval-source-map 配置进行增量编译
在大多数状况下,cheap-module-eval-source-map 是最好的选择