Webpack
一、webpack基础介绍
1、入口entry
// 进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。
module.exports = {
entry: './path/to/my/entry/file.js'
};
单个入口
用法:
entry: string|Array<string>
jsmodule.exports = { entry: './path/to/my/entry/file.js' }; module.exports = { entry: { main: './path/to/my/entry/file.js' } };
对象语法
js// 用法:entry: {[entryChunkName: string]: string|Array<string>} module.exports = { entry: { app: './src/app.js', adminApp: './src/adminApp.js' } }; // 多页面应用程序 module.exports = { entry: { pageOne: './src/pageOne/index.js', pageTwo: './src/pageTwo/index.js', pageThree: './src/pageThree/index.js' } };
2、输出output
// output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
}
};
// filename 用于输出文件的文件名
多个入口起点
jsmodule.exports = { entry: { app: './src/app.js', search: './src/search.js' }, output: { filename: '[name].js', path: __dirname + '/dist' } }; // 写入到硬盘:./dist/app.js, ./dist/search.js
3、模式mode
// 通过选择 development, production 或 none 之中的一个,来设置 mode 参数,你可以启用 webpack 内置在相应环境下的优化。其默认值为 production。
module.exports = {
mode: 'production'
};
4、loader
loader
支持链式传递。链中的每个loader
会将转换应用在已经处理过的资源上。loader
可以是同步的,也可以是异步的。loader
运行在Node.js中,并且可以执行任何Node.js可以做到的操作loader
可以通过options
对象配置
//webpack 只能理解 JavaScript 和 JSON 文件。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 模块,以供应用程序使用,以及被添加到依赖图中
const path = require('path');
module.exports = {
output: {
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
}
};
使用loader
的三种方式:配置、内联、CLI;
配置
js// loader 从右到左地取值(evaluate)/执行(execute)。在下面的示例中,从 sass-loader 开始执行,然后继续执行 css-loader,最后以 style-loader 为结束。 module.exports = { module: { rules: [ { test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader', options: { modules: true } }, { loader: 'sass-loader' } ] } ] } };
内联
js// 使用 ! 将资源中的loader分开 import Styles from 'style-loader!css-loader?modules!./styles.css';
CLI
js// 这会对 .jade 文件使用 jade-loader,以及对 .css 文件使用 style-loader 和 css-loader。 webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
5、插件plugin
// loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量。
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件
module.exports = {
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
},
plugins: [
// 插件可以携带参数/选项
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
二、webpack的热更新
HMR全称Hot Module Replacement,模块热替换;开启方式:
const webpack = require('webpack')
module.exports = {
// ...
devServer: {
// 开启 HMR 特性
hot: true
// hotOnly: true
}
}
三、webpack的构建流程
初始化流程:从配置文件和shell语句中读取合并参数,并初始化需要使用的插件和配置插件等执行环境所需要的参数
编译构建流程:从Entry发出,针对每一个Module穿行调用对应的Loader去翻译文件内容,再找到该Module依赖的Module,递归的进行编译处理
compile开始编译
执行run方法之后首先会触发complie,构建一个Compilation对象,会进行:执行模块创建、依赖收集、分块、打包等
make从入口分析模块及其依赖的模块,创建这些模块对象
完成Compilation对象之后,开始从entry入口文件开始读取,主要执行_addModuleChain()函数
build-module构建模块
调用配置的loaders,将模块转成标准的JS模块,输出对应的抽象语法树AST,方便webpack后面对代码分析
seal封装构建结果
主要是生成chunks,对chunks进行一系列的优化操作,并生成主要输出的代码
emit把各个chunk输出到结果文件
根据配置的路径和文件名机型输出
输出流程:对编译后的Module组合成Chunk,把Chunk转换成文件,输出到文件系统
四、webpack proxy工作原理
基本行为就是接收客户端发送的请求后转发给其他服务器,中间服务器:webpack-dev-server
1、webpac-dev-server
// ./webpack.config.js
const path = require('path')
module.exports = {
// ...
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000,
proxy: {
'/api': {
target: 'https://api.github.com'
}
}
// ...
}
}
五、loader
对模块的源码进行转换,在import或加载模块时预处理文件。
在webpack中,任何文件都是模块
六、Plugin
是一种计算机应用程序,他和主应用程序相互交互,提供特定的功能;始终顿寻一定规范的应用程序接口编写出来的程序,只能运行在程序规定的系统下,因为其需要调用原纯净系统提供的函数库,或者数据。
const HtmlWebpackPlugin = require('html-webpack-plugin'); //
const webpack = require('webpack'); //
module.exports = {
...
plugins: [
new webpack.ProgressPlugin(),
new HtmlWebpackPlugin({ template: './src/index.html' }),
],
};
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
compiler.hooks.run.tap(pluginName, (compilation) => {
console.log('webpack 构建过程开始 ');
});
}
}
module.exports = ConsoleLogOnBuildWebpackPlugin;
/*
compiler hook的tap第一个参数,应该是驼峰命名的插件名称
整个编译周期的声明周期钩子如下:
entry-option:初始化option
run
compile:开始编译,在创建compilation之前
compilation:生成好了compilation对象
make:从entry开始递归分析依赖,准备对每一个模块进行build
after-compile:编译build过程结束
emit:在将内存中assets内容写到磁盘文件夹之前
after-emit:在将内存中assets内容写到磁盘文件夹之后
done:完成所有的编译过程
failed:编译失败的时候
*/
八、怎么提高webpack的构建速度
1、优化loader配置
在使用loader时,可以通过配置include、exclude、test属性来匹配文件
2、合理使用resolve.extensions
解析文件时,自动添加扩展名
3、优化resolve.modules
module.exports = {
resolve: {
// 使用绝对路径知名第三方模块存放位置,以减少搜索步骤
// 其中 __dirname 表示当前工作目录
modules: [path.resolve(__dirname, 'node_modules')]
},
};
4、优化resolve.alias
配置alias减少查找过程
module.exports = {
...
resolve:{
alias:{
"@":path.resolve(__dirname,'./src')
}
}
}
5、使用DLLPlugin插件
6、使用cache-loader
7、terser启动多线程
8、合理使用sourceMap
九、前端项目优化
1、JS代码压缩
const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
...
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true //
})
]
}
}
2、CSS代码压缩
通常是去除无用的空格等
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
module.exports = {
// ...
optimization: {
minimize: true,
minimizer: [
new CssMinimizerPlugin({
parallel: true
})
]
}
}
3、HTML文件代码压缩
module.exports = {
plugin: [
new HtmlwebpackPlugin({
minify: {
minifyCSS: false, // 是否压缩CSS
},
collapseWhitespace: false, // 是否折叠空格
removeComments: true // 是否移除注释
})
]
}
4、文件大小压缩
new ComepressionPlugin({
test:/\.(css|js)$/, // 哪些文件需要压缩
threshold:500, // 设置多大开始压缩
minRatio:0.7, // 压缩的比例
algorithm:"gzip", // 采用的压缩算法
})