认识webpack5
- webpack 是一个模块打包器(构建工具)。它的主要目标是将 JavaScript 文件打包在一起,打包后的文件用于在线浏览器中使用,但它也能够胜任转换(transform)、打包(bundle)或包裹(package)任何资源(resource or asset)。
- 官网 中文文档
了解webpack 原理和概念
- 树结构:在一个入口文件中引入所有资源,形成所有依赖关系树状图
- 模块:模块就是模块可以是ES6模块也可以是commonJS 或者AMD模块,对于webpack 来说,所有的资源(css,img…)
- chunk:打包过程中被操作的模块文件叫做chunk,例如异步加载一个模块就是一个chunk
- bundle: bundle是最后打包后的文件,最终文件可以和chunk长的一模一样,但是大部分情况下他是多个chunk的集合
- 为了优化最后生产出的bundle 数量可能不等于 chunk 的数量,因为有可能多个chunk被组合到了一个Bundle 中
webpack 安装和体验
- 1、创建项目目录: webpack-demo
- 2、进入目录初始化NPM操作: npm init -y (-y = -yes, i=install)
- 3、安装webpack及微博pack-cli: npm install webpack webpack-cli -D (-D = --save-dev )
- 4、创建src 目录或根据需要创建下面的子目录
- 5、在src 下创建一些js 文件,和一个主入口文件index.js
- 6、控制台运行命令: webpack --mode development (开发环境)
控制台运行命令: webpack --mode production (生产环境) - 7、可以使用node 运行打包后的资源,也可以使用HTML引入打包后的资源
webpack 的5个核心概念
- entry
- 入口(entry)指示 webpack 以哪个文件作为入口起点开始打包,分析构建内部依赖图。 - output
- 输出( output)指示webpack 打包后的资源 bundles 输出到哪里,以及如何命名 - loader
- loader 让webpack 能够去处理那些非JavaScript资源css、img等,将它们处理成webpack 能够识别的资源,可以理解成一个翻译过程(webpack自身只能理解js 和json) - plugins
- 插件(plugins)可用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等。 - mode
- 模式 (mode) 指示 webpack 使用相应模式的配置。
开发模式(development) :配置比较简单,能让代码本地调试运行的环境
生产模式( production) :代码需要不断优化达到性能最好。能让代码优化上线运行的环境。
- 都会自动启用一些插件,生产模式使用插件更多
多个入口和多个出口的情况–入口文件
- String: 单入口,打包成一个chunk ,输出一个bundle 文件,chunk 的名称为默认。
entry: './src/index.js',
- Array : 多入口,写多个入口,所有入口文件形成一个chunk (名称默认) ,输出只有一个bundle ,chunk 名称默认
entry:["./src/two.js","./src/index.js"]
- Object: 多入口,有几个入口文件就生产几个chunk ,并输出几个bundle 文件,chunk 的名称是key
entry:{
two: "./src/two.js",
index:"./src/index.js"
}
- 特殊用法:
entry:[
**//数组中所有入口文件生成一个chunk ,输出一个bundle 文件,chunk的名称是key**
onetwo:["./src/one.js","./src/two.js"],
**//形成一个chunk ,输出一个 bundle 文件**
index:'./src/index.js'
]
webpack 打包html 资源
- 使用插件(plugins)对HTML 文件进行处理(html-webpack-plugin)
- 使用步骤:1.下载 2.引入 3. 使用
- 下载安装:npm i html-webpack-plugin -D
- 引入插件: const HtmlWebpackPlugin = require(‘html-webpack-plugin’);
- 使用插件:
plugins:[
//功能: 默认会创建一个空的HTML 文件,自动引入打包输出的所有资源 (JS/CSS)
//new HtmlWebpackPlugin()
//通过参数可以输出有结构的HTML 资源
new HtmlWebpackPlugin({
//复制 './src/index.html' 文件,并引入打包输出的所有资源(JS/CSS)
template:"./src/index.html",
//默认是index.html 名称,通过 filename 设置输出文件名称
//filename:"demo.html"
})
],
html-webpack-plugin 插件生成的内存中的页面已帮饿哦们创建并正确引用了打包编译生成的资源(JS/CSS)
压缩JS 和HTMl 代码
- JS 代码只需要设置成生产模式( production)模式,会自动压缩
- 压缩HTML 方法:
//通过参数可以输出有结构的HTML 资源
new HtmlWebpackPlugin({
//压缩html 代码
minify:{
//移除空格
collapseWhitespace:true,
//移除注释
removeComments:true
}
})
webpack打包多个html 开发案例
- 多html 的规律是需要多个entry,每个html 一个entry,同时需要新建多个HtmlWebpackPlugin
//多个entry
entry:{
vendor:['jquery','./src/js/common.js'],
index:"./src/js/index.js",
cart:"./src/js/cart.js"
}
//负责打包html 文件 将js 注入到html 中,minify 压缩html
new HtmlWebpackPlugin({
filename:"index.html",
template:"./src/index.html",
chunks:["index","vendor"],
minify:{
removeComment:true,
collapseWhitespace:true
}
}),
new HtmlWebpackPlugin({
filename:"cart.html",
template:"./src/cart.html",
chunks:["cart","vendor"]
})
webpack 打包css 资源
- 需要使用npm 下载安装两个 loader 帮我们完成打包
1.css-loader 的作用是处理 css 中 @import 和url 这样的外部资源
2.style-loader 的作用是吧样式插入到 DOM 中,方法是在head 中插入一个style 标签,并把样式写入到这个标签的 innerHTML 里
npm i css-loader style-loader -D
webpack
module:{
rules:[
{
test:/\.css$/,
//从右到左 从下到上
//一个 loader:'css-style'
use:['style-loader','css-loader']
}
]
},
webpack打包less 或sass资源
- 因为css 只是单纯的属性描述,它并不具有变量 、条件语句等,css 的特性导致了它难组织和维护
- Sass 和 Less 都属于CSS 预处理器,定义了一种新的语言,其基本思想是用一种专门的编程语言,为CSS 增加一些编程的特性,将CSS作为目标生产文件,然后开发者使用这种语言进行CSS 编码工作,
- Less 需要使用npm 下载less 包 和less-loader
- Sass 需要使用npm 下载node-sass包和 sass-loader
module:{
rules:[
{test:/\.css$/,use:['style-loader','css-loader']},
{test:/\.less$/,use:['style-loader','css-loader','less-loader']},
{test:/\.scss$/,use:['style-loader','css-loader','sass-loader']}
]
},
提取CSS 为单独文件
- css内容是打包在js 文件中的,可以使用“ mini-css-extract-plugin” 插件提取成单独的CSS 文件。
- 在webpack.config.js 中引入插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
2. 在plugins 模块中使用插件
plugins:[ New MiniCssExtractPlugin()],
//或通过参数 filename 重新命名提取的 css 文件名
new MiniCssExtractPlugin({ filename:'./css/demo.css'})
3. 在CSS 的rules 中,使用 MiniCssExtractPlugin.loader取代style-loader,提取js中CSS 内容为单文件
{test:/\.css$/,use:[MiniCssExtractPlugin.loader,'css-loader']}
//如果sass 和 less 也提取成单独css文件,也一样将style-loader 换成 MiniCssExtractPlugin.loader
{test:/\.scss$/,use:[MiniCssExtractPlugin.loader,'css-loader','sass-loader']}
处理CSS 的兼容性
- 需要使 postcss 处理, 下载两个包 postcss-loader 和postcss-preset-env
npm i postcss-loader postcss-preset-env -D - postcss 会找到 package.json 中的 browserslist 里面的配置,通过配置加载css 的兼容性
- 修改loader 的配置,新版需要写 postcss.config.js ,less 和sass 兼容性同理
webpack.config.js
{test:/\.css$/,use:[MiniCssExtractPlugin.loader,'css-loader','postcss-loader']}
{test:/\.scss$/,use:[MiniCssExtractPlugin.loader,'css-loader','sass-loader','postcss-loader']}
postcss.config.js
module.exports = {
plugins:[
require('postcss-preset-env')()
]
}
package.json
"browserslist":[
"> 0.2%",
"last 2 versions",
"not dead"
]
压缩CSS
- 使用 optimize-css-assets-webpack-plugin插件压缩CSS内容
1. 引入插件
const OptimizeCssAssetsWebpackPlugin= require('optimize-css-assets-webpack-plugin');
2. 使用插件
plugins:[new OptimizeCssAssetsWebpackPlugin()],
webpack 打包图片资源
- 需下载 url-loader 和 file-loader 两个包
rules:[
//{test:/\.(png|jpg|jpeg|gif)$/,use:['url-loader',{loader:'file-loader',optopns:{}}]}
{
test:/\.(png|jpg|jpeg|gif)$/,
loader:'url-loader',
options:{
publicPath:'./images/',
outputPath:'images/',
limit: 1024 *8,
name:'[name][hashi:10].[ext]' //源文件名[name].[ext]
}
},
{
test:/\.html$/,
loader:'html-loader'
}
]
webpack 其他资源打包
{
exclude:/\.(js|json|html|css|less|scss|png|gif|jpg|jpeg)$/, //反向选择(除了)
loader:'file-loader',
options:{
outputPath:'font/',
publicPath:'/font',
name:'[name].[ext]'
}
}
对js 语法配置语法检查 eslint
- eslint 是一个开源的 js 代码检查工具,初衷是为了让程序员可以创建自己的检查规则。实际生产中,团队内往往会定制一套统一的标准,让整个团队的编码风格达到一致。
- eslint 其实与 webpack 没有任何关系,两者并不相互依赖,甚至一般情况下我们并不会在 webpack 中进行 eslint 的配置,可以单独使用。
- 语法检查使用 eslint-loader,并基于 eslint 包,只用来检查js 语法。
- 注意只检查自己的写的js源代码,第三方库是不用检查的,可以在npmjs.com中查看规则。
- 需要使用js来的规则库来检查代码 “airbnb” ,需要 eslint-config.airbnb-base 和 eslint-plugin-import 两个包
- npm i eslint-loader eslint eslint-config-airbnb-base eslint-plugin-import -D
webpack.config.js
{
//eslint 只检查js 语法
test:/\.js$/,
//只检查自己写的代码,不检查第三方库的代码
exclude:/node_modules/,
loader:'eslint-loader',
options:{
fix:true
}
}
package.json
"eslintConfig":{
"extends":"airbnb-base"
}
//下一行eslint 所有规则失效
//eslint-disable-next-line
console.log(111);
开发服务器devServer 配置
- devServer给我们提供了开发过程的服务器,是一个使用了 express 的Http服务器,它的作用主要是为了监听资源文件的改变,该http服务器和client 使用了 websocket 通信协议,只要资源文件发生改变,webpack-dev-server 就会实时的进行编译。
- 只会在内存中编译,不会有任何输出,下载webpack-dev-server 包
- webpack-dev-server 并不能读取你的webpack.config.js 的配置output
- 启动devServer指令为: npx webpack server 本目录执行
- webpack5 无法刷新,解决:添加配置: target: ‘web’
- npm i webpack-dev-server -D
webpack.config.js
/*模式 mode 指示 webpack 使用相应模式的配置
开发模式(development) :配置 比较简单,能让代码本地调式运行的环境
生产模式(production): 代码需要不断优化达到性能最好。能让代码优化上线运行的环境
*/
devServer:{
port:3001,
compress:true,
open:true
}
环境的优化
- 开发环境的优化
- 打包构建速度
- 优化代码调试 - 生产环境的优化
- 代码运行的性能
HMR(模块热替换)
- 模块热替换(Hot Modele Replacement 即 HMR)是webpack 提供的最有用的功能之一,它允许在运行时更新各种模块,而无需进行完全刷新。
- 启用这个功能,只需要修改一下webpack.config.js 的配置,使用webpack 内置的HMR 插件就可以了,在devServer 中使用hot 参数。
- 启用webpack 内置的HMR 插件后,modele.hot 接口就会暴露在index.js 中,接下来需要在index.js 中配置告诉webpack接受HMR 的模块。
- 1.样式HMR 功能,在开发环境中使用 style-loader
- 2.HTM的HMR 功能,默认也没有HMR功能(不用做HMR 功能),需要在entry入口中引入html 文件。
- 3.js的HMR功能,默认没有HMR 功能,只能处理非入口文件的js 文件。
- 启用 webpack 内置的HMR 插件后,module.hot 接口 就会暴露在index.js 中,接下来需要在index.js中配置告诉 webpack 接受HMR 的模块
webpack.config.js
devServer:{
port:3001,
compress:true,
open:true,
hot:true
}
index.js
if(module.hot){
module.hot.accept('./print.js',function(){
console.log("print.js这个文件内容被改变")
})
}
去除项目里面的死代码
- 去除没有用到的JS 代码
- Webpack 通过 tree-shaking 去掉了实际上并灭有使用的 js 代码来减少包的大小。
- 1.必须使用es6 模块化 2.开启production 环境 - 去除没有用到的css
- 比如我们经常使用的 BootStrap(140KB) 就可以减少到只有35KB 大小
- webpack 使用 purgecss-webpack-plugin 去除无用的css
webpack.config.js
const {resolve,json} = require('path');
const PurgecssPlugin = require('purgecss-webpack-plugin');
const glob = require('glob');
const PATHS = {src:join(_dirname,'src')}
new PurgecssPlugin({
paths:glob.sync('$(PATHS.src)/**/*',{nodir:true})
})