初学webpack
(0)安装及前言
0.简介
简单来说就是将我们使用的超当前版本所能识别的代码或其他资源打包编译后形成浏览器能够认识的代码
1.需要安装的工具(按需安装)
webpack:npm i webpack -g
webpack-cli:npm i webpack-cli -g (使我们能够使用命令的形式打包文件)
style-loader:npm i style-loader -D (-D为局部安装)创建style标签,将js中的样式资源插入进行,添加到head中生效
css-loader:npm i style-loader -D 将css文件变成commonjs模块加载js中,里面内容是样式字符串
html-webpack-plugin: 打包html文件
less-loader:npm i less-loader -D 将less文件转化为css文件
ur1-loader:
file-loader:处理img文件打包
webpack-dev-server:指令为npx webpack-dev-server 。在内存中编译,不会产生输出,自动编译,自动打开浏览器、自动刷新
mini-css-extract-plugin:提取css到单独的文件
postcss-loader
postcss-preset-env:处理兼容性问题
optimize-css-assets-webpack-plugin:压缩css
eslint-loader:
eslint:
eslint-config-airbnb-base:
eslint-plugin-import:后面两个是使用airbnb语法检查,全部都是用于语法检查
babel-loader
@babel/ preset-env
@babel/core
@babel/ployfill
core-js:js兼容性配置
workbox-webpack-plugin:pwa相关
thread-loader:多进程打包
add-asset-html-webpack-plugin:自动引入某个包输出,并在html中自动引入该资源
2.webpack相关配置文件:webpack.config.js
Entry:入口文件,即打包文件从哪里开始,类似于java项目中的main文件(这句不懂也没关系)
单入口:entry : '【相对路径】 ',
多入口:entry:{ // 多入口:有一个入口,最终输出就有一个bundle
index: './src/js/index.js ' ,
test: './src/js/test.js'}
Output:输出文件,即编译好的文件会放在哪里,这里可能会用到获取当前的绝对路径(代码:)
output: {
filename: 'js/ [name]. [ contenthash : 10].js ', // [name]:在多入口文件时,取文件名(key),单文件时可以自命名或...
path: resolve(__dirname,'build' )},
Loader:指导webpack处理那些非js文件【在文件中文module】
Plugins:插件的声明区,插件可以帮webpack执行更广的任务。
mode:development / production
devServer:开发服务器
optimization:
externals:
(1)生产环境
1.样式资源打包:module (包括css、less等,不过use的设置不同,需要的自行百度)
rules: [{
test: /\.css$ / , // 匹配哪些文件,正则形式
use:[ // 使用哪些loader进行处理l,use数组中loader执行顺序:从右到左,从下到上依次执行
'style-loader ' , // 创建style标签,将js中的样式资源插入进行,添加到head中生效
'css-loader' // 将css文件变成commonjs模块加载js中,里面内容是样式字符串
'less-loader' ] // 将less文件转化为css文件 【如果仅打包css,则不需要这句话】
提取css到单独的文件夹
const MiniCssExtractPlugin = require( 'mini-css-extract-plugin');
module中
use:[ // 使用哪些loader进行处理l,use数组中loader执行顺序:从右到左,从下到上依次执行
MiniCssExtractPlugin.loader, //取代style-loader,将css取出到单独文件
'css-loader' // 将css文件变成commonjs模块加载js中,里面内容是样式字符串
'less-loader' ] // 将less文件转化为css文件 【如果仅打包css,则不需要这句话】
plugins中
new MinicssExtractPlugin({ filename: 'css/built.css'}) //对输出的文件重命名
兼容性处理
use:{ 【module】
MiniCssExtractPlugin.loader, //取代style-loader,将css取出到单独文件
'css-loader' // 将css文件变成commonjs模块加载js中,里面内容是样式字符串
{
loader: 'postcss-loader' ,
options: {
ident: 'postcss ',
plugins: () =>[
require( 'postcss-preset-env' )() }} // postcss的插件
package.json中需要新加一个属性browserslist【相关配置可在git上搜索,查看配置】
"browserslist" : {
"development":[ ... ],
"production" : [ ... ] }
压缩css
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin') 【引入】
new OptimizeCssAssetsWebpackPlugin() 【在plugins中】
2.打包html资源:Plugins
const HtmlwebpackPlugin = require( ' html-webpack-plugin' ); 【引入】
new HtmlwebpackPlugin({
template: './ src/index.html' }) // 复制 ‘./src/index.htm1’文件,并自动引入打包输出的所有资源(JS/css)
html代码压缩:【HtmlwebpackPlugin函数的参数】
minify : {
collapsewhitespace: true, //移除空格
removeComments: true} //移除注释
3.打包图片资源:module
test: /.(jpglpnglgif)$/ ,
loader: 'ur1-loader ', //使用一个loader
options: {
limit: 8* 1024 //图片大小小于8kb,就会被base64处理,减少请求数量(减轻服务器压力),但图片体积会更大(文件请求速度更慢)
esModule: false //解决:关闭url-loader的es6模块化,使用commonjs解析
name: '[hash: 10]. [ext]' } // [hash: 10]取图片的hash的前10位 [ext]取文件原来扩展名
4.其他资源:module
exclude: /\.( cssljs / htm1 / less)$/ , //排除css/js/html资源
loader: 'file-loader ' ,
options: {
name: "[hash: 10]:[ext] '}
5.js语法检查
package.json:
"eslintConfig": {
"extends" : "airbnb-base"}
module
test: /.js$/ ,
exclude: /node_modules/ , //只检查自己写的代码,下载的依赖不管
loader: 'eslint-loader' ,
options: {}}
js的兼容性处理【module】
1.基础处理:只能转化基础语法,例如promise就不能转化
test: /.js$/ ,
exclude: /node_modules/ , //只检查自己写的代码,下载的依赖不管
loader: 'babel-loader' ,
options: {
presets : [ [ '@babel/preset-env ' ] ] } //预设:指示babel做怎么样的兼容性处理
2.全部处理
在需要的js文件中引入@babel/ployfill即可
3.按需处理
options->presets -> 数组([ '@babel/preset-env ' ])内
{ useBuiltIns: 'usage, //按需加载
corejs: { version: 3}, // 指定core-js版本
targets: { chrome: '60',firefox: '60',ie: '9' .....} //指定兼容性做到哪个版本浏览器
js压缩
在开发模式下,js代码会自动被压缩,不用配置,在生产环境则不用管压缩
(2)开发环境
基本配置和生产环境一致
1.开发服务器:
devserver:{
contentBase: resolve(__dirname,'build ' ) , //项目构建后的路径
compress: true, //启动gzip压缩,编译更快
port: 3000, //端口号
open: true} //自动打开浏览器
(3)性能优化
1.HMR:hot module replacement 热模块替换/模块热替换
开启:devserver下,hot:true
样式文件: 可以使用HMR功能:因为style-loader内部实现了
js文件: 默认不能使用HMR功能,需要修改js文件,支持HMR的代码
if ( module.hot) { //一旦 module.hot为true,说明开启了HMR功能。--> 让HMR功能代码生效
module.hot.accept( ' ./ print.js ', function ( ) { ... }) // 方法会监听 print.js 文件的变化,一旦发生变化,其他默认不会重新打包构建。//会执行后面的回调函数
html文件: 默认不能使用HMR功能.同时会导致问题: html文件不能热更新了(因此不需要HMR)
2.source-map:代码调试(源代码到打包代码的映射)
写法:[ inline- | hidden- | eval- ] [ nosources- ] [ cheap- [module- ] ] source-map
外部:在文件外部生成文件; 内联:显示在编译后文件内部;且内联构建速度更快
source-map:外部,错误代码准确信息和源代码的错误位置
inline-source-map:内联(一个总的内联source-map)错误代码准确信息和源代码的错误位置
hidden-source-map:外部,错误代码准确信息和构建后的代码位置
eval-source-map:内联(每一个文件都会有一个内联source-map)错误代码准确信息和源代码的错误位置
nosources-source-map:外部,错误代码准确信息,但没有任何源代码信息
cheap-source-map:外部,错误代码准确信息和源代码的错误位置,只能精确到行
cheap-module-source-map:外部,错误代码准确信息和源代码的错误位置,会将loader的source-map也加到映射中
要求:
1.开发环境:速度快,调试友好
速度:eval-cheap > eval > inline > cheap
调试:source-map > cheap-module > cheap
2.生产环境:源代码隐藏,调试友好,但内联会使代码体积变大,因此一般使用外部方式
nosources-source-map
hidden-source-map
3.oneOf:loader只会匹配一个
写法:
oneOf:[..loader..]
注意:
不能有两个配置处理同一类文件
配置:
endorce:'pre' //优先执行【loader中】
4.缓存技术
写法:【options -> 和 presets同级】
cacheDirectory : true
问题:开启强缓存时,代码的修改并不会反映到浏览器上
解决:为生成的js / css文件添加一个哈希值。 filename : 'css / built. [ hash : 10].css'
新问题:css和js生成的hash值相同,js变动也会导致css重新被打包
解决:
1.chunkhash:根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样问题:js和css的hash值还是一样的,但因为css是在js中被引入的,所以同属于一个chunk,不能解决问题
2.contenthash:根据文件的内容生成hash值。不同文件hash值一定不同
5.tree shaking:树摇,去除没有使用过的代码
前提:1.使用SE6模式;2.开启production模式
packsge.json中,若配置sideEffects,则可能会过滤掉css和@babel/ployfill等文件
解决:sideEffects:["*.css"]
6.code split:代码分割
多入口【Entry】
optimization:{ //1.可以将node_modules中代码单独打包一个chunk最终输出; 2.自动分析多入口chunk,将相同的文件打包形成一个单独的chunk
splitchunks: { chunks : 'all' } }
js代码单独打包
import( '/*webpackChunkName: 'test*/ ./test ' ) ///*webpackChunkName: 'test*/ 为单独打包的文件起一个别名
.then( ( ) =>{ }) 加载成功
.catch( ( ) =>{ }) 加载失败
7.懒加载与预加载
懒加载:和上文中的js单独打包的写法一致,使用时才会加载
预加载:webpackPrefetch: true(和webpackChunkName: 'test'位置相同),在使用前会加载,使用时准备好了,在浏览器空闲时加载
8.PWA:渐进式网络开发应用程序,了解即可,现在用到的很少了。
引入:const workboxWebpackPlugin = require( ' workbox-webpack-plugin')
使用:new workboxwebpackPlugin.GenerateSw({ // 1.帮助serviceworker快速启动 2.删除旧的serviceworker 【plugins】
clientsclaim: true,
skipwaiting : true})
入口文件:if ( ' serviceworker' in navigator) {
window.addEventListener( ' load ', () => {
navigator.serviceworker.register( ' / service-worker.js ' )
.then(() => {})
.catch(( ) =>{})});});
"env" : { "browser" : true } // package.json中eslintConfig中添加,作用为使eslint认识window的环境变量
9.多进程打包
在js兼容性配置中的use配置首添加'thread-loader'即可
当然写可以写成对象形式
loader: 'thread-loaaer ,
options:{
workers: 2 }, // 进程2个
10.externals:防止将某些包打包到最终输出中。这样的需要自己引入需要的文件
externals: i
jquery: 'jQuery'} //忽略库名-- npm包名
11.dll:动态链接库
新建一个webpack.dll.js,运行 webpack --config webpack.dll.js
内容:
const { resolve } = require( ' path ' );
const webpack = require( ' webpack ' );
module.exports = {
entry: {
jquery: ['jquery'] }, // 1. 最终打包生成的[name] -->jquery 2. [ 'jquery' ] -->要打包的库是jquery
output: {
filename: ‘[name].js ',
path: resolve(_dirname,'dll '),
library: '[name]_[hash]' } , //打包的库里面向外暴露出去的内容叫什么名字
plugins:[
new webpack.DllPlugin( { // 打包生成一个manifest.json -->提供和jquery映射
name: '[name]_[ hash] ', // 映射库的暴露的内容名称
path :resolve( __dirname . 'dll/manifest.json')))], //输出文件路径
mode: 'production'};
webpack.config.js引用
new webpack.D11ReferencePlugin({ // 告诉webpack哪些不需要打包
manifest: resolve(_dirname,'dll/manifest.json ' )})
new AddAssetHtmlwebpackPlugin({
filepath: resolve(__dirname,'dl1/jquery.js ')})
(4)externals详细配置
splitChunks:{
chunks:'all'
minsize: 30*1024,//分割的chunk最小为30kbmaxsiza: 6,l/最大没有限制
minChunks: 1,//要提取的chunk最少被引用1次
maxAsyncRequests: 5, //按需加载时并行加载的文件的最大数量
maxInitialRequests: 3, //入口js文件最大并行请求数量
automaticNameDelimiter: '~', //名称连接符
name : true, //可以使用命名规则
cacheGroups: { //分割chunk的组,node_modules文件会被打包到 vendors 组的chunk中。--> vendors~xxx.js,满足上面的公共规则,如:大小超过30kb,至少被引用一次。
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10}, //优先级
default: {
minchunks: 2, //要提取的chunk最少被引用2次
priority: -20, //优先级
reuseExistingChunk: true}}, //如果当前要打包的模块,和之前已经被提取的模块是同一个,就会复用,而不是重新打包模块
hashruntimeChunk :{ //将当前模块的记录其他模块的hash单独打包为一个文件runtime,防止修改a文件导致b文件中引用的hash值变化
name: entrypoint => 'runtime-${entrypoint.name}}
minimizer:[ //配置生产环境的压缩方案:js和css
new TerserwebpackPlugin( {
cache: true, //开启缓存
parallel: true, //开启多进程打包
sourceMap: true}) //启动source-map
(5)webpack5
学习时完成度71%,暂时先空着