Webpack
1. 介绍
- 一种构建工具,静态模块打包器
- 把前端资源文件(js、css、img、json、less)等作为模块打包成静态资源(bundle)
2. 五个核心概念
2.1 Entry(入口)
有很多个需要打包的文件,从哪个文件开始打包
入口(Entry)指示 Webpack以哪个文件为入口起点开始打包,分析构建内部依赖图。
2.2 Output(输出)
把需要打包的文件打包后弄到哪
输出(Output)指示 Webpack 打包后的资源bundles输出到哪里去,以及如何命名。
2.3. Loader
webpack只认识js,loader能帮webpack认识别的(css,img等)
Loader 让 Webpack能够去处理那些非JavaScript文件(webpack自身只理解JavaScript)
2.4. Plugins(插件)
干loader做不到的活,压缩,优化等
插件(Plugins)可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等。
2.5. Mode(模式)
webpack用的相应配置。分为开发模式(development)和生产模式(production)
模式(Mode)指示 Webpack使用相应模式的配置。
选择 | 描述 | 特点 |
---|---|---|
development | 会将process.env.NODE_ENV的值设为development。启用NamedChunksPlugin和 NamedModulesPlugin。 | 能让代码本地调试运行的环境 |
production | 会将process.env.NODE_ENV 的值设为production.会将process.env.NODE_ENV 的值设为production.FlagIncludedChunksPlugin,ModuleConcatenationPlugin,NoEmitOnErrorsPlugin,OccurrenceOrderPlugin, SideEffectsFlagPlugin和UglifyJsPlugin. | 能让代码优化上线运行的环境 |
3. 怎么打包文件
3.1 初始化
npm init
选默认值
3.2 下包
- -g全局安装,在任何位置
npm i webpack webpack-cli -g
安装一次就可以,在安装会替代以前的版本 - -D本地安装,在项目根目录,
npm i webpack webpack-cli -D
添加到开发依赖
3.3初体验
3.3.1 写要打包文件的代码
- 根目录新建src(源代码目录)
- 根目录新建build(webpack打包后)
- 在src文件夹中新建xx.js,该文件里写js代码
//import xx from 'xx'或import 'xx' 引入需要打包的其他文件
function add(a,b){
return a+b
}
console.log(add(1,2));
3.3.2 打包js文件
在根目录打开命令行工具
开发环境:webpack ./src/index.js -o ./build/built.js --mode=development
生产环境:webpack ./src/index.js -o ./build/built.js --mode=production
使用webpack,把./src/xx.js作为入口文件,打包到./xx/ 模式用xx
- 可以在js中导入json文件
import a from '../data/data.json'
console.log(a);
- webpack能处理js/json资源,不能处理css/img等其他资源
- 生产环境和开发环境将ES6模块化编译成浏览器能识别的模块化~
- 生产环境比开发环境多一个压缩js代码。
3.5 打包样式资源
3.5.1 打包css文件
- src所在目录下定义配置文件webpack.config.js
const {resolve} = require('path')
module.exports={
//webpack配置
//入口起点
entry:'./src/index.js',
//输出
output:{
//输出文件名
filename:'built.js',
//输出路径
//__dirname node.js的变量,代表当前文件的目录绝对路径
path:resolve(__dirname,'build')
},
module:{
rules:[
//详细loader配置
{
test:/\.css$/,
//使用多个loader要用use,如果是一个只需要写loader:''即可。比如loader:'url-loader'
use:[
//use数组中loader执行顺序:从右到左,从上到下 依次执行
//创建style标签,将js中的样式资源插入进行,添加到head中生效
'style-loader',
//将css文件变成commonjs模块加载js中,里面内容是样式字符串
'css-loader'
]
}
]
},
//plugins的配置
plugins:[
//详情plugins
],
//模式
mode:'development' //开发模式
}
- 项目根目录下载style-loader包和css-loader包
npm i css-loader style-loader -D
- 打包`webpack
3.5.2打包 less文件
- 在webpack.config.js的rules中添加
{
test:/\.less$/,
use:[
'style-loader',
'css-loader',
'less-loader'
]
}
- 下less-loader包和less包
npm i less-loader less -D
- index.js中引入改该less文件
- 打包
webpack
3.6 打包html资源
- 下包
npm i html-webpack-plugin -D
- 在webpack.config.js中引入html-webpack-plugin插件
const HtmlWebpackPlugin = require('html-webpack-plugin')
在plugins中添加
new HtmlWebpackPlugin({
template: './src/index.html' //要打包的html的路径
})
- 打包
webpack
3.7打包图片资源
-
下包
npm i url-loader file-loader -D
npm i html-loader -D
-
在webpack.config.js的rules中添加
//不能处理html里面的图片
{
test:/\.(jpg|png|gif)$/,
loader:'url-loader',
options:{
//图片大小小于8kb,就会被base64处理
//优点:减少请求数量(减轻服务器压力)
//缺点:图片体积会更大(文件请求速度更慢)
limit: 8*1024
}
},
//处理html中的图片
{
//负责引入html文件的img图片(被url-loader处理)
test: /\.html$/,
loader: 'html-loader',
options:{ esModule:false }
}
3.7.1 可能出现的错误及解决方法
- 如果出现两次图片,不显示,请在loader加上type:‘javascript/auto’
打包压缩图片后打开背景图片不显示:原因是webpack5.0像url-loader,file-loder都是废弃不会直接使用的。如果想要使用这些废弃的旧功能,加上type: javascript/auto
{
// 匹配哪些文件,test就是代表匹配了哪些文件
test: /\.(png|jpg)$/,
loader: 'url-loader',// 这个还需要安装file-loader
options: {
// 图片转换为base64模式
// 图片体积会变大
limit: 8 * 1024,
name:'[hash:10].[ext]',
},
type:'javascript/auto'
}
- 打包
webpack
3.8打包其他资源
在webpack.config.js的rules中添加
{
//除了以下资源
exclude:/\.(css|js|html)$/,
loader:'file-loader'
}
4.开发服务器devServer
4.1. 下包npm i webpack-dev-server
4.2. 配置
webpack.config.js中的module.exports添加devServer
//开发服务器devServer:用来自动化(自动编译,自动打开浏览器,自动刷新浏览器)
//特点:只会在内存中编译打包,不会有任何输出
//启动devServer指令为:npm webpack-dev-server
devServer:{
contentBase:resolve(__dirname,'build'),
compress:true,
port:3000,
open:true
},
4.3. 启动devServer
指令为npx webpack-dev-server
4.4 可能出现的错误及解决方法
4.4.2 改了配置一定要重新启动
Class constructor ServeCommand cannot be invoked without ‘new’
解决:删了node_modules ,重新npm install
4.4.3 html-webpack-plugin版本问题
Cannot read property ‘tap’ of undefined
解决:“html-webpack-plugin”: “^3.2.0”
4.4.4webpack版本问题
webpack5启动
解决:npx webpack serve
我的配置为:
"devDependencies": {
"@webpack-cli/serve": "^1.5.1",
"css-loader": "^5.2.7",
"file-loader": "^6.2.0",
"html-loader": "^2.1.2",
"html-webpack-plugin": "^5.3.2",
"less": "^4.1.1",
"less-loader": "^10.0.1",
"style-loader": "^3.2.1",
"url-loader": "^4.1.1",
"webpack": "^5.46.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0"
},
5.配置开发环境
1. entry:
‘起点文件的路径’
2. output:
{
2.1 filename
:‘路径 / 输出文件名’
2.2 path
:resolve(__dirname,‘输出到哪个文件夹’)
}
3. module
:{
3.1 relues
:[
//loader配置
{
//检测需要打包的文件类型
3.1.1 test
: /.xx文件后缀名
或者
3.1.1 exclude
: /.需要排除的文件后缀名/
3.1.2 use
:[
‘用到的loader1’,
‘用到的loader2’
]
或者 只用到一个loader时
3.1.2 loader
:‘用到的loader’
3.1.3 options
:{
3.1.3.1limit
:图片大小(小于会转化base64模式),
3.1.3.2 name
:’[hash:10].[ext]’ (用哈希值前十位+后缀名命名) ,
3.1.3.3 outputPath
:‘想把该类型文件打包到哪个文件夹’
}
}
]
}
4. plugins
:[
new HtmlWebpackPlugin({
template: ‘路径/打包的html’
})
]
5. mode
:‘用什么模式(开发者|生产者)’
6. devServer
:{
contentBase:resolve(__dirname,‘要运行项目的目录’),
compress:true,(是否启动zgip压缩)
post:启用端口号
open:是否自动打开
}
结合代码参考更有效哦
//resolve用来拼接绝对路径的方法
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
/*
loader:下载,使用
plugins:下载,引用,使用
*/
module.exports = {
//webpack配置
//入口起点
entry: '/src/js/index.js',
//输出
output: {
//输出文件名
filename: 'js/built.js',
//输出路径
//__dirname node.js的变量,代表当前文件的目录绝对路径
path: resolve(__dirname, 'build')
},
module: {
rules: [
//详细loader配置
{
test: /\.css$/,
use: [
//use数组中loader执行顺序:从右到左,从上到下 依次执行
//创建style标签,将js中的样式资源插入进行,添加到head中生效
'style-loader',
//将css文件变成commonjs模块加载js中,里面内容是样式字符串
'css-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
{
// 匹配哪些文件,test就是代表匹配了哪些文件
test: /\.(png|jpg)$/,
loader: 'url-loader',// 这个还需要安装file-loader
options: {
// 图片转换为base64模式
// 图片体积会变大
limit: 8 * 1024,
name:'[hash:10].[ext]',
outputPath:'imgs'
},
//webpack5以上
// type:'javascript/auto'
},
{
//负责引入html文件的img图片(被url-loader处理)
test: /\.html$/,
loader: 'html-loader',
options:{ esModule:false }
},
{
exclude:/\.(css|html|less|jpg|png|js|json)$/,
// test: /\.ttf$/,
loader:'file-loader',
options:{
name:'[hash:10].[ext]',
outputPath:'media'
}
}
]
},
//plugins的配置
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
//模式
mode: 'development' , //开发模式
//开发服务器devServer:用来自动化(自动编译,自动打开浏览器,自动刷新浏览器)
//特点:只会在内存中编译打包,不会有任何输出
//启动devServer指令为:npm webpack-dev-server
devServer:{
contentBase:resolve(__dirname,'build'),
compress:true,
port:3000,
open:true
},
}
6.css提取成单独文件
6.1.下包
npm i mini-css-extract-plugin -D
6.2. 配置
6.2.1 在webpack.config.js中引入
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
6.2.2使用loader配置
css的use里
//style-loader
MiniCssExtractPlugin.loader,
6.2.3 plugins里添加插件
new MiniCssExtractPlugin({
//css文件输出位置
filename:'css/built.css'
})
6.2.4webpack启动
6.3.可能出现的错误及解决方法
6.3.1 没有去掉style-loader
[webpack-cli] Failed to load ‘F:\web\sy\sy-webpack\webpack.config.js’ config
[webpack-cli] ReferenceError: style is not defined
解决办法://style-loader
6.3.2webpack版本问题
ERROR in [entry] [initial] css/built.css
(0 , _identifier.getUndoPath) is not a function
解决办法:把webpack换5"webpack": “^5.46.0”
7.css兼容性处理
7.1.下包
npm i postcss-loader postcss-preset-env -D
7.2.使用loader的配置
css 的use里面加
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
require('postcss-preset-env')()
]
},
}
7.3.设置package.josn
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
},
7.4.设置node环境变量:
process.env.NODE_ENV = ‘development’
7.5.webpack启动
7.6.可能出现的错误及解决办法
7.6.1代码语法错误
ERROR in ./src/css/index.css Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js): ModuleBuildError: Module build failed (from ./node_modules/postcss-loader/dist/cjs.js): ValidationError: Invalid options object. PostCSS Loader has been initialized using an options object that does not match the API schema.
解决办法:
- 可能是打错代码了
- 将postcss-loader换成3.0.0版本
- 用最新语法
https://www.npmjs.com/package/postcss-loader
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
require('postcss-preset-env')()
]
},
}
把以上代码换成以下代码
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
[
"postcss-preset-env",
{
// Options
},
],
,
},
}
}
8.压缩css
8.1下包
npm i optimize-css-assets-webpack-plugin -D
8.2 在webpack.config.js中引入
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
8.3plugins中添加插件
new OptimizeCssAssetsWebpackPlugin()
8.1webpack启动
9.JS语法检查eslint
9.1. 使用loader配置
{
test:/\.js$/,
exclude:/node_modules/,
loader:'eslint-loader',
options:{
fix:true //自动修复
}
}
9.2. 下包
npm i eslint-loader eslint eslint-config-airbnb-base eslint-plugin-import -D
9.3. 设置package.json
添加
"eslintConfig":{
"extends":"airbnb-base"
},
9.4. 下一行eslint规则失效
写在想不检测代码的上一行
eslint-disable-next-line
10. js兼容性处理
10.1 基本js兼容性处理–>@babel/preset-env
问题:只能转换基本语法,如promise不能转换
- loader
{
test:/\.js$/,
exclude:/node_modules/,
loader:'babel-loader',
options:{
//预设 :指示babel做怎么样的兼容性处理
presets:['@babel/preset-env']
}
},
- 下包
npm i babel-loader @babel/core @babel/preset-env -D
- webpack
10.2 全部js兼容性处理–>@babel/polyfill
问题:我只要解决部分兼容性问题,但是将所有兼容性代码全部引入,体积太大了
- 下包@babel/polyfil1
- index.js引入
import ‘@babel/polyfill’
10.3 需要做兼容性处理的就做:按需加载–> core-js
- 下包npm i core-js -D
- 修改loader
presets: [
[
'@babel/preset-env', {
useBuiltIns: 'usage',
corejs: {
version: 3
},
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
]
11.压缩html、js
- 把mode模式改为production
12.webpack性能优化
- 开发环境性能优化
- 生产环境性能优化
12.1开发环境性能优化
- 优化打包构建速度
- 优化代码调试
12.2生产环境性能优化
- 优化打包构建速度
- 优化代码运行的性能
13.HMR热模块替换
HMR: hot module replacement热模块替换/模块热替换
作用:一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块)极大提升构建速度
样式文件:可以使用HMR功能:因为style-loader内部实现了~js文件:默认不能使用HMR功能
在devserver里加hot: true
js文件: 默认无该HMR功能,需要添加支持该功能的代码,
只能处理非入口js文件
html文件:默认不能使用HMR功能.同时会导致问题: html文件不能热更新了~(不用做HNR功能)
解决:修改entry入口,将html文件引入
入口文件 entry: [’./src/js/index.js’, ‘./src/index.html’]