尚硅谷2020最新版Webpack5实战教程(从入门到精通),哔哩哔哩链接:https://www.bilibili.com/video/BV1e7411j7T5?p=1
环境参数: Nodejs 10版本以上、webpack 4.26版本以上
预备技能: 基本Nodejs知识和Npm指令、熟悉ES6语法
webpack
是一种前端资源构建工具,一个静态模块打包器(module bundler
)。 在 webpack 看来, 前端的所有资源文件
(js/json/css/img/less/...
)都会作为模块处理。 它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle
)。
入口(Entry
)指示 webpack 以哪个文件为入口起点开始打包,分析构建内部依赖图。例如从index.js
这个起点出发
输出(Output
)指示 webpack 打包后的资源 bundles 输出到哪里去,以及如何命名。
Loader
让 webpack 能 够 去 处 理 那 些 非 JavaScript 文 件 (webpack 自 身 只 理 解 JavaScript
),例如css、img
插件(Plugins
)可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩, 一直到重新定义环境中的变量等。
1.在vscode
中新建一个文件夹,右键在终端中打开
2.输入 npm init
,初始化npm,
3.接着输入webpack的包名
,其他按enter默认即可
4.然后下载包并指定为全局安装,输入
npm i webpack webpack-cli -g
这里下载了两个包,一个为webpack
,一个为webpack-cli
,使我们通过webpack-cli这个包的指令去使用webpack内部的功能,-g
表示全局安装,将来可以直接通过指令去调用这两个包。这里即使你已经安装过这两个包,也可以再次输入,他会自动覆盖旧的包
5.然后本地安装,输入 ,
npm i webpack webpack-cli -D
-D
的意思是将webpack添加到开发依赖,webpack下载的所有东西都属于开发依赖,不属于生产依赖
6.之后新建的文件夹会出现以下的三个文件
7.接着在自己建的文件夹下新建src
和bulid
文件夹,src表示源代码,bulid表示代码通过webpack打包处理之后输出的目录
8.在src下新建index.js
作为webpack的入口起点文件
index.js
/*
index.js: webpack入口起点文件
1. 运行指令:
开发环境:webpack ./src/index.js -o ./build/built.js --mode=development
webpack会以 ./src/index.js 为入口文件开始打包,打包后输出到 ./build/built.js
整体打包环境,是开发环境
生产环境:webpack ./src/index.js -o ./build/built.js --mode=production
webpack会以 ./src/index.js 为入口文件开始打包,打包后输出到 ./build/built.js
整体打包环境,是生产环境,生产环境会压缩代码
2. 结论:
1. webpack能处理js/json资源,不能处理css/img等其他资源
2. 生产环境和开发环境将ES6模块化编译成浏览器能识别的模块化~
3. 生产环境比开发环境多一个压缩js代码。
*/
// import './index.css';
import data from './data.json';
console.log(data);
function add(x, y) {
return x + y;
}
console.log(add(1, 2));
data.json
{
"name": "jack",
"age": 18
}
9.然后运行开发环境指令 ,
webpack ./src/index.js -o ./build/built.js --mode=development
-o
为Output,意思是输出到.build/built.js
这个路径。
Hash
为每次打包都会生成一个唯一的哈希值,built.js
为打包资源
10.通过 node .\build\built.js
指令便可直接运行built.js文件
11.在html中引入webpack打包后的资源
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./build/built.js">script>
head>
<body>
body>
html>
结果如下:
因为webpack只能识别js
文件,所以要想识别其他文件必须在webpack的配置文件里进行配置,将其转换为js。
1.新建index.css、index.js、index.less、webpack.config.js
配置文件
index.css
html, body{
margin: 0;
padding: 0;
height: 100%;
background-color: pink;
}
index.js
// 引入样式资源
import './index.css';
import './index.less';
index.less
#title {
color: #fff;
}
webpack.config.js
/*
webpack.config.js webpack的配置文件
作用: 指示 webpack 干哪些活(当你运行 webpack 指令时,会加载里面的配置)
所有构建工具都是基于node.js平台运行的~模块化默认采用commonjs。
*/
// resolve用来拼接绝对路径的方法
const { resolve } = require('path');
module.exports = {
// webpack配置
// 入口起点
entry: './src/index.js',
// 输出
output: {
// 输出文件名
filename: 'built.js',
// 输出路径
// __dirname 为node.js的变量,代表当前文件的目录绝对路径,即代表“03.打包样式资源”这个路径,
//后面的“build”表示这个目录下的build路径
path: resolve(__dirname, 'build')
},
// loader的配置
module: {
rules: [
// 详细loader配置
// 不同文件必须配置不同loader处理
{
// 匹配哪些文件
test: /\.css$/,
// 使用哪些loader进行处理
use: [
// 注意,use数组中loader执行顺序:从右到左,从下到上 依次执行
// 创建style标签,将js中的样式资源插入进行,添加到head中生效
'style-loader',
// 将css文件变成commonjs模块加载js中,里面内容是样式字符串
'css-loader'
]
},
{
test: /\.less$/,
use: [
// 创建style标签,将js中的样式资源插入进行,添加到head中生效
'style-loader',
// // 将css文件变成commonjs模块加载js中,里面内容是样式字符串
'css-loader',
// 将less文件编译成css文件,需要下载 less-loader和less
'less-loader'
]
}
]
},
// plugins的配置
plugins: [
// 详细plugins的配置
],
// 模式
mode: 'development', // 开发模式
// mode: 'production' 生产模式
}
2.为了防止我们每新建一个案例就导一次包,我们可以利用node找包找不到,去上一级找的特点
直接给整个项目导入包,我们输入
npm i webpack webpack-cli -D
再输入
npm i css-loader style-loader less less-loader -D
这里下载了4个包,css-loader
和style-loader
为css样式打包所要用到的,还有less
(这里less不下载也可以)和less-loader
为将less文件转换为css所需要的
3.之后输入webpack
或者webpack ./src/index.js -o ./build/built.js --mode=development
进行打包
4.新建index.html
文件引入打包好的js文件,查看效果是否实现
index.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<script src="./build/built.js">script>
<body>
<h1 id="title">111h1>
body>
html>
1.对新建的项目(打包html)进行npm init
,配置好信息后自动生成package.json、package-lock.json 和node-modules
这三个文件,之后新建index.js
打包入口文件、webpack.config.js
配置文件,
index.js
function add(x, y) {
return x + y;
}
console.log(add(2, 3));
webpack.config.js
/*
loader: 1. 下载 2. 使用(配置loader)
plugins: 1. 下载 2. 引入 3. 使用
*/
const { resolve } = require('path');
// 引入下载的 html-webpack-plugin 这个插件
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
]
},
plugins: [
// plugins的配置,打包html需要 html-webpack-plugin 这个包
/* new HtmlWebpackPlugin()功能:默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS),
所以我们可以在里面加入 template: './src/index.html' 这样就会将我们的html引入它创建出来的html当中
*/
// 需求:需要有结构的HTML文件
new HtmlWebpackPlugin({
// 复制 './src/index.html' 文件,并自动引入打包输出的所有资源(JS/CSS)
template: './src/index.html'
})
],
mode: 'development'
};
2.然后把这个案例右键在终端打开下载html-webpack-plugin
这个包,输入
npm i html-webpack-plugin -D
3.再输入webpack
进行打包
1.对新建的项目(打包图片资源)进行npm init
,配置好信息后自动生成package.json、package-lock.json 和node-modules
这三个文件,之后新建index.js
打包入口文件、webpack.config.js
配置文件、index.less
、index.html
index.js
import './index.less';
index.less
#box1{
width: 100px;
height: 100px;
background-image: url('./vue.jpg');
background-repeat: no-repeat;
background-size: 100% 100%;
}
#box2{
width: 200px;
height: 200px;
background-image: url('./react.png');
background-repeat: no-repeat;
background-size: 100% 100%;
}
#box3{
width: 300px;
height: 300px;
background-image: url('./angular.jpg');
background-repeat: no-repeat;
background-size: 100% 100%;
}
index.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>webpacktitle>
head>
<body>
<div id="box1">div>
<div id="box2">div>
<div id="box3">div>
<img src="./angular.jpg" alt="angular">
body>
html>
webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.less$/,
// 要使用多个loader处理用use
use: ['style-loader', 'css-loader', 'less-loader']
},
{
// 问题:默认处理不了html中img图片
// 处理图片资源
test: /\.(jpg|png|gif)$/,
// 使用一个loader
// 下载 url-loader和file-loader,因为url-loader依赖file-loader
loader: 'url-loader',
options: {
// 图片大小小于8kb,就会被base64处理,这里的数字随便自己写
// 优点: 减少请求数量(减轻服务器压力)
// 缺点:图片体积会更大(文件请求速度更慢)
limit: 8 * 1024,
// 问题:因为url-loader默认使用es6模块化解析,而html-loader引入图片是commonjs
// 解析时会出问题:[object Module],即在html中的引入的图片src值会
// 变为
// 解决:关闭url-loader的es6模块化,使用commonjs解析,新版webpack已解决这个问题
esModule: false,
// 给图片进行重命名,如果不重命名的话图片默认使用生成的哈希值进行命名,导致图片名字过长,影响加载速度
// [hash:10]取图片的hash的前10位
// [ext]取文件原来扩展名
name: '[hash:10].[ext]'
}
},
{
test: /\.html$/,
// 处理html文件的img图片(负责引入img,从而能被url-loader进行处理)
loader: 'html-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
结构目录如下:注意vue.jpg
图片由于大小小于8k,已被默认转换为base64
的图片编码显示,
2.右键在终端打开,输入
npm i style-loader css-loader less-loader url-loader file-loader html-loader -D
style-loader
和css-loader
为css样式表所需要的,
style-loader
和css-loader
和less-loader
为less所需要的,
url-loader
依赖file-loader
,为less或css中导入background-image: url('./react.png');
这个图片所需要的,
html-loader
为html中引入图片所需要的
3.再输入webpack
进行打包,打包好后bulit.js
引入的html文件如下
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>webpacktitle>
head>
<body>
<div id="box1">div>
<div id="box2">div>
<div id="box3">div>
//src值为自定义重命名的哈希值的前十位+后缀名
<img src="830bf3c820.jpg" alt="angular">
<script type="text/javascript" src="built.js">script>body>
html>
目录结构:
index.js
// 引入 iconfont 样式文件
import './iconfont.css';
webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
// 打包其他资源(除了html/js/css资源以外的资源)
{
// 排除css/js/html资源
exclude: /\.(css|js|html|less)$/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
index.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>webpacktitle>
head>
<body>
<span class="iconfont icon-icon-test">span>
<span class="iconfont icon-icon-test2">span>
<span class="iconfont icon-icon-test3">span>
<span class="iconfont icon-icon-test1">span>
body>
html>
打包好后bulit.js
引入的index.html,查看效果
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>webpacktitle>
head>
<body>
<span class="iconfont icon-icon-test">span>
<span class="iconfont icon-icon-test2">span>
<span class="iconfont icon-icon-test3">span>
<span class="iconfont icon-icon-test1">span>
<script type="text/javascript" src="built.js">script>body>
html>
需要先下载webpack-dev-server
这个包,输入npm i webpack-dev-server -D
启动devServer指令为:npx webpack-dev-server
停止devServer指令:快捷键ctrl+c
webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
// 打包其他资源(除了html/js/css资源以外的资源)
{
// 排除css/js/html资源
exclude: /\.(css|js|html|less)$/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development',
// 开发服务器 devServer:用来自动化(自动编译,自动打开浏览器,自动刷新浏览器~~)
// 特点:只会在内存中编译打包,不会有任何输出,即不会更新(改变)bulid打包文件夹中的文件,
// 即使把bulid删掉也能照样显示
// 启动devServer指令为:npx webpack-dev-server
devServer: {
// 项目构建后路径
contentBase: resolve(__dirname, 'build'),
// 启动gzip压缩
compress: true,
// 端口号,即在浏览器中输入http://localhost:3000/ 即可访问
port: 3000,
// 自动打开浏览器 即输入npx webpack-dev-server后自动打开浏览器
open: true
}
};
webpack.config.js
/*
开发环境配置:能让代码运行
运行项目指令:
webpack 会将打包结果输出出去
npx webpack-dev-server 只会在内存中编译打包,没有输出
*/
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 引入一个对象
module.exports = {
// 入口
entry: './src/js/index.js',
// 输出
output: {
// 文件名
filename: 'js/built.js',
/*
输出的文件路径,一般是一个绝对路劲,而绝对路径一般需要引入一个node.js的核心模块path,
path的方法叫resolve方法,用来处理绝对路径
__dirname 为node.js的变量,代表当前文件的目录绝对路径,即代表“开发环境配置”这个路径,
后面的“build”表示这个目录下的build路径
*/
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
{
// 处理less资源,less和css会一起输出到bulit.js文件当中
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
// 处理css资源
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
// 处理(css、less)图片资源
test: /\.(jpg|png|gif)$/,
// url-loader通过es6-modules解析
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
// 关闭es6模块化,使用commonjs解析,这是为了防止模块不一样导致解析失败,新版webpack已解决这个问题
esModule: false,
// 将图片输出到imgs下
outputPath: 'imgs'
}
},
{
// 处理html中img资源,html-loader通过commonjs解析
test: /\.html$/,
loader: 'html-loader'
},
{
// 处理其他资源
exclude: /\.(html|js|css|less|jpg|png|gif)/,
// url-loader是在file-loader基础上做了详细的优化,多了一个limit的功能,
// 即转为base64的图片格式,file-loader就是原封不动的将资源输出出去
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
// // 将其他资源输出到media下
outputPath: 'media'
}
}
]
},
// 插件,处理html资源需要插件,插件需要引入才能使用,
// 即上方的const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [
// plugins的配置
new HtmlWebpackPlugin({
// 表示以某个文件为模板
template: './src/index.html'
})
],
mode: 'development',
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true
}
};
打包后引入bulit.js
的index.html文件
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>开发环境配置title>
head>
<body>
<h1>开发环境配置h1>
<span class="iconfont icon-icon-test">span>
<span class="iconfont icon-icon-test2">span>
<span class="iconfont icon-icon-test3">span>
<span class="iconfont icon-icon-test1">span>
<div id="box">div>
<img src="data:image/jpeg;base64,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" alt="vue">
<img src="imgs/13c51607b8.png" alt="react">
<script type="text/javascript" src="js/built.js">script>body>
html>
需要先下载插件进行从js中提取css出来,输入
npm i mini-css-extract-plugin -D
webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
//引入提取css为一个文件的插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: [
// 创建style标签,将样式放入输出的html页面上
// 'style-loader',
// 这个loader取代style-loader。作用:提取js中的css成单独文件
MiniCssExtractPlugin.loader,
// 将css文件整合到js文件中,然后在通过下方的mini-css-extract-plugin插件处理成一个css文件
'css-loader'
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({
// 对输出的css文件进行重命名
filename: 'css/built.css'
})
],
mode: 'development'
};
输入webpack
即可打包,
需先下载插件,能帮助postcss识别某些环境,从而加载指令的配置,让兼容器做到精确到某一个浏览器的版本
npm i postcss-loader postcss-preset-env -D
webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
/* 设置nodejs环境变量,这里是为了测试在最近的如下添加的最近的一个chrome、火狐、safari中的兼容性。
即在package.json中配置的开发环境(development)的适配
如果不设置这个的话,默认是会使用生产模式的,跟下方的 mode: 'development'是没有关系的*/
/*
设置使用开发环境打包,会将display: flex; backface-visibility: hidden;编译
为display: flex;-webkit-backface-visibility: hidden;backface-visibility: hidden;
因为我们这里在开发模式中设置的是兼容最近一个chrome、火狐、safari的最新版本,
所以他不会将display: flex;编译
不设置使用开发环境打包,默认使用生产模式打包,会将display: flex; backface-visibility: hidden;
编译为 display: -webkit-box; display: flex;
-webkit-backface-visibility: hidden;backface-visibility: hidden;这里就对display:flex做了兼容
*/
// process.env.NODE_ENV = 'development';
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
/*
css兼容性处理:postcss --> postcss-loader postcss-preset-env
下方的require('postcss-preset-env')()表示 帮postcss找到package.json中
browserslist里面的配置,通过配置加载指定的css兼容性样式,
所以还要在package.json文件中加入browserslist的配置,如下:
"last 1 chrome version",表示兼容最新的一个Chrome的版本
"browserslist": {
// 开发环境 --> 设置node.js环境变量:process.env.NODE_ENV = development
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
// 生产环境:默认是看生产环境 ">0.1%",表示大于99.9%的浏览器
"not dead",不要已经死了的浏览器,比如ie10
"not op_mini all" 表示不要op_mini的浏览器,因为他已经不存在了,不需要再兼容
"production": [
">0.1%",
"not dead",
"not op_mini all"
]
}
*/
// 使用loader的默认配置,即直接'postcss-loader',
// 修改loader的配置
{
loader: 'postcss-loader',
// 在option里修改配置
options: {
// 固定写法
ident: 'postcss',
plugins: () => [
// postcss的插件,要在package.json中实现browserslist里面的配置
require('postcss-preset-env')()
]
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({
filename: 'css/built.css'
})
],
mode: 'development'
// mode:'production'
};
在package.json中配置browserslist
{
"name": "text88",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.8.4",
"@babel/polyfill": "^7.8.3",
"@babel/preset-env": "^7.8.4",
"add-asset-html-webpack-plugin": "^3.1.3",
"babel": "^6.23.0",
"babel-loader": "^8.0.6",
"core-js": "^3.6.4",
"css-loader": "^3.6.0",
"eslint": "^6.8.0",
"eslint-config-airbnb-base": "^14.0.0",
"eslint-loader": "^3.0.3",
"eslint-plugin-import": "^2.20.1",
"file-loader": "^5.0.2",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"less": "^3.11.3",
"less-loader": "^5.0.0",
"mini-css-extract-plugin": "^0.9.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"style-loader": "^1.2.1",
"terser-webpack-plugin": "^2.3.5",
"thread-loader": "^2.1.3",
"url-loader": "^3.0.0",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0",
"workbox-webpack-plugin": "^5.0.0"
},
"dependencies": {
"jquery": "^3.4.1"
},
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.1%",
"not dead",
"not op_mini all"
]
},
"eslintConfig": {
"extends": "airbnb-base",
"env": {
"browser": true
}
},
"sideEffects": [
"*.css"
],
"description": ""
}
设置为开发模式(development
)打包,即在package.config.js
中加入node.js
环境变量process.env.NODE_ENV = 'development';
表示用开发模式打包,跟其下方的mode: 'development'
没有关系,对display:flex
没有做兼容,因为这里我们是设置开发模式是适配最近的一个Chrome、火狐、Safari的版本:
设置为生产模式(production
)打包后的css兼容,默认的,不用设置,其对display:flex
做了兼容:
下载压缩css的插件:
npm i optimize-css-assets-webpack-plugin -D
然后在webpack.config.js
中引入,然后通过new OptimizeCssAssetsWebpackPlugin()
调用即可压缩
const { resolve } = require('path');
/*为html文件中引入的外部资源如script、link动态添加每次compile后的hash,
防止引用缓存的外部文件问题
可以生成创建html入口文件,比如单页面可以生成一个html文件入口,
配置N个html-webpack-plugin可以生成N个页面入口
*/
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 引入将css从打包好的js文件中抽取成一个独立的css文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 引入压缩css插件
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
// 设置nodejs环境变量
// process.env.NODE_ENV = 'development';
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
// postcss的插件
require('postcss-preset-env')()
]
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
/*根据自己的指定的模板文件来生成特定的 html 文件。这里的模板类型可以是任意你喜欢的模板,
可以是 html, jade, ejs, hbs, 等等,
但是要注意的是,使用自定义的模板文件时,需要提前安装对应的 loader, 否则webpack不能正确解析。
*/
template: './src/index.html'
}),
new MiniCssExtractPlugin({
// 指定提取出来的css文件
filename: 'css/built.css'
}),
// 通过new调用,压缩css
new OptimizeCssAssetsWebpackPlugin()
],
mode: 'development'
};
下载插件,
npm i eslint-loader eslint eslint-config-airbnb-base eslint-plugin-import -D
webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
/*
语法检查: 需要eslint-loader而eslint-loader又依赖于eslint
注意:只检查自己写的源代码,第三方的库是不用检查的,所以加入下方的
exclude: /node_modules/,表示排除node_modules,不写的话会出现许多错误
设置检查规则,一般用airbnb规则:
package.json中eslintConfig中设置~
"eslintConfig": {
"extends": "airbnb-base"
}
其中"extends": "airbnb-base"表示继承下载的eslint-config-airbnb-base,
会自动加载里面的配置进行检查
airbnb规则需要这个插件 --> eslint-config-airbnb-base ,
而又依赖于 eslint-plugin-import eslint 这两个插件,
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
options: {
// 自动修复eslint的错误,例如function add(x, y) { return x + y;}中x,后面没有加空格
fix: true
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
在package.json中配置eslintConfig
{
"name": "text88",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.8.4",
"@babel/polyfill": "^7.8.3",
"@babel/preset-env": "^7.8.4",
"add-asset-html-webpack-plugin": "^3.1.3",
"babel": "^6.23.0",
"babel-loader": "^8.0.6",
"core-js": "^3.6.4",
"css-loader": "^3.6.0",
"eslint": "^6.8.0",
"eslint-config-airbnb-base": "^14.2.0",
"eslint-loader": "^3.0.4",
"eslint-plugin-import": "^2.21.2",
"file-loader": "^5.0.2",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"less": "^3.11.3",
"less-loader": "^5.0.0",
"mini-css-extract-plugin": "^0.9.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"style-loader": "^1.2.1",
"terser-webpack-plugin": "^2.3.5",
"thread-loader": "^2.1.3",
"url-loader": "^3.0.0",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0",
"workbox-webpack-plugin": "^5.0.0"
},
"dependencies": {
"jquery": "^3.4.1"
},
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.1%",
"not dead",
"not op_mini all"
]
},
"eslintConfig": {
"extends": "airbnb-base",
"env": {
"browser": true
}
},
"sideEffects": [
"*.css"
],
"description": ""
}
注意:
function add(x, y) {
return x + y;
}
/* console.log(add(2, 5));在实际的项目上线中是不需要的,eslint会警告,如果想要忽略的直接加入
// eslint-disable-next-line就可以,表示下一行eslint所有规则都失效
(下一行不进行eslint检查),注意就是下方注释的形式
*/
// eslint-disable-next-line
console.log(add(2, 5));
因为es6的语法IE浏览器是不支持的,所以我们提供三种方法
下载插件:
npm i babel-loader @babel/preset-env @babel/core -D
然后webpack,只能转换基本语法(将const转换为var,将箭头函数转换为function)
下载插件
npm i @babel/polyfill -D
然后在index.js中引入即可,因为不是babel插件,不用在webpack.config.js中引入
import '@babel/polyfill';
// const属于es6的关键字,将function改为箭头函数
const add = (x, y) => {
return x + y;
};
console.log(add(2, 5));
const promise = new Promise(resolve => {
setTimeout(() => {
console.log('定时器执行完了~');
resolve();
}, 1000);
});
console.log(promise);
然后webpack打包,只要解决部分兼容性问题,但是将所有兼容性代码全部引入,体积太大了~
下载插件
npm i core-js -D
index.js
// import '@babel/polyfill'; 这个为全部js兼容,但是体积过于大,不推荐
// const属于es6的关键字,将function改为箭头函数
const add = (x, y) => {
return x + y;
};
console.log(add(2, 5));
const promise = new Promise(resolve => {
setTimeout(() => {
console.log('定时器执行完了~');
resolve();
}, 1000);
});
console.log(promise);
webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
/*
js兼容性处理:babel-loader @babel/core
1. 基本js兼容性处理 --> @babel/preset-env
问题:只能转换基本语法(将const转换为var,将箭头函数转换为function),
如promise高级语法不能转换,需要下载@babel/preset-env babel-loader @babel/core 这三个插件
2. 全部js兼容性处理 --> @babel/polyfill
问题:我只要解决部分兼容性问题,但是将所有兼容性代码全部引入,体积太大了~
3. 需要做兼容性处理的就做:按需加载 --> core-js
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
// 预设:指示babel做怎么样的兼容性处理,默认情况我们用 '@babel/preset-env'
presets: [
[
'@babel/preset-env',
// {}表示一个对象
{
// 按需加载
useBuiltIns: 'usage',
// 指定core-js版本
corejs: {
version: 3
},
// 指定兼容性做到哪个版本浏览器
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
]
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
// 压缩html代码,不需要压缩html的话,直接去掉minify即可
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true
}
})
],
// js压缩,生产环境下会自动压缩js代码
mode: 'production'
};
webpack.config.js
const { resolve } = require('path');
// 从bulit.js中提取css为一个单独文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 压缩css
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
// 对html资源进行处理
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 定义nodejs环境变量:决定使用browserslist的哪个环境
// process.env.NODE_ENV = 'development';
process.env.NODE_ENV = 'production';
// 复用loader
const commonCssLoader = [
// 替换style-loader,把css样式不放在html中,提取出一个css文件
MiniCssExtractPlugin.loader,
'css-loader',
{
// postcss-loader表示对css样式进行兼容性处理,
loader: 'postcss-loader',
// 通过options修改postcss-loader的配置
options: {
// 表示默认配置为postcss
ident: 'postcss',
/* 表示用postcss-preset-env这个插件里面默认的配置对postcss进行处理,
记住这里还需要在package.json中定义browserslist,
browserslist默认使用的是生产环境的配置,要想使用开发模式的配置还需要设置node.js的环境变量,
即上方的process.env.NODE_ENV = 'production';
*/
plugins: () => [require('postcss-preset-env')()]
}
}
];
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
// rules表示规则
rules: [
{
test: /\.css$/,
// 注意use数组默认执行顺序是从下往上执行的
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']
},
/*
正常来讲,一个文件只能被一个loader处理。
当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
先执行eslint 在执行babel,因为eslint是做语法检查的,而babel-loader会将es6语法转换为es5语法,
所以如果先经过语法转换在检查就会出现语法错误
所以要优先处理的loader加上enforce: 'pre'
*/
{
test: /\.js$/,
// 通过exclude属性排除第三方库、插件的检查
exclude: /node_modules/,
// 优先执行
enforce: 'pre',
// 注意此次还要在package.json中配置eslintConfig --> 我们使用airbnb这个规则
loader: 'eslint-loader',
options: {
// 自动修复一些错误
fix: true
}
},
{
// 对js做兼容性处理
test: /\.js$/,
exclude: /node_modules/,
// babel-loader会将es6语法转换为es5语法
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: {version: 3},
targets: {
chrome: '60',
firefox: '50'
}
}
]
]
}
},
{
// 对图片进行处理
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
// 这里是为了优化性能,将大小小于8k的图片转换为base64的图片编码格式,
// 同时对文件的名字进行处理, outputPath: 'imgs',表示输出的路径
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
// 使用commjs进行解析
esModule: false
}
},
{
// 处理html中的图片问题
test: /\.html$/,
loader: 'html-loader'
},
{
// 处理其他文件,通过排除法
exclude: /\.(js|css|less|html|jpg|png|gif)/,
// file-loader表示原封不动的输出文件资源,而url-loader是他的改进版,可以对资源进行改进
loader: 'file-loader',
options: {
// 输出目录
outputPath: 'media'
}
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.css'
}),
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
// 以指定的html模板创建新的文件
template: './src/index.html',
minify: {
// 对html进行压缩
collapseWhitespace: true,
// 去除html的注释
removeComments: true
}
})
],
mode: 'production'
};
package.json
{
"name": "text88",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.8.4",
"@babel/polyfill": "^7.8.3",
"@babel/preset-env": "^7.8.4",
"add-asset-html-webpack-plugin": "^3.1.3",
"babel": "^6.23.0",
"babel-loader": "^8.0.6",
"core-js": "^3.6.4",
"css-loader": "^3.6.0",
"eslint": "^6.8.0",
"eslint-config-airbnb-base": "^14.2.0",
"eslint-loader": "^3.0.4",
"eslint-plugin-import": "^2.21.2",
"file-loader": "^5.0.2",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"less": "^3.11.3",
"less-loader": "^5.0.0",
"mini-css-extract-plugin": "^0.9.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"style-loader": "^1.2.1",
"terser-webpack-plugin": "^2.3.5",
"thread-loader": "^2.1.3",
"url-loader": "^3.0.0",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0",
"workbox-webpack-plugin": "^5.0.0"
},
"dependencies": {
"jquery": "^3.4.1"
},
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.1%",
"not dead",
"not op_mini all"
]
},
"eslintConfig": {
"extends": "airbnb-base",
"env": {
"browser": true
}
},
"sideEffects": [
"*.css"
],
"description": ""
}
* 开发环境性能优化
* 优化打包构建速度
* HMR
* 优化代码调试
* source-map
* 生产环境性能优化
* 优化打包构建速度 * oneOf
* babel缓存 * 多进程打包
* externals * dll
* 优化代码运行的性能 * 缓存(hash-chunkhash-contenthash)
* tree shaking * code split
* 懒加载/预加载 * pwa
/*
HMR: hot module replacement 热模块替换 / 模块热替换
作用:一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块),极大提升构建速度
开启HMR:直接在webpack.config.js中加入 hot: true 即可开启,
但是注意当修改了webpack配置,新配置要想生效,必须重启webpack服务
在终端按 ctrl+c,输入指令 y 终止webpack,然后输入npx webpack-dev-server
样式文件:可以使用HMR功能:因为style-loader内部实现了~
js文件:默认不能使用HMR功能 --> 需要修改js代码,添加支持HMR功能的代码
即在打包入口的js文件中加入如下代码:
if (module.hot) {
// 一旦 module.hot 为true,说明开启了HMR功能。 --> 让HMR功能代码生效
module.hot.accept('./print.js', function() {
// 方法会监听 print.js 文件的变化,一旦发生变化,其他模块不会重新打包构建。
// 会执行后面的回调函数
print();
});
}
注意:HMR功能对js的处理,只能处理非入口js文件的其他文件。因为入口文件会将其他文件引入,
一旦入口文件发生变化,又会将其他文件引入重新加载
html文件: 默认不能使用HMR功能.同时会导致问题:html文件不能热更新了~
(不用做HMR功能,因为只有一个文件,当他刷新时整个页面都会刷新)
解决:修改entry入口,将html文件引入,
*/
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: ['./src/js/index.js', './src/index.html'],
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
{
// 处理less资源
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
// 处理css资源
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
// 处理图片资源
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
// 关闭es6模块化
esModule: false,
outputPath: 'imgs'
}
},
{
// 处理html中img资源
test: /\.html$/,
loader: 'html-loader'
},
{
// 处理其他资源
exclude: /\.(html|js|css|less|jpg|png|gif)/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'media'
}
}
]
},
plugins: [
// plugins的配置
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development',
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true,
// 开启HMR功能
// 当修改了webpack配置,新配置要想生效,必须重新webpack服务
hot: true
}
};
例如:
/*
source-map: 一种 提供源代码到构建后代码映射 技术 (如果构建后代码出错了,通过映射可以追踪源代码错误)
[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
开启方式:在webpack.config.js中加入 devtool:上方的组合值
source-map:外部
错误代码准确信息 和 源代码的错误位置
inline-source-map:内联,即生成在bulit.js当中
只生成一个内联source-map
错误代码准确信息 和 源代码的错误位置
hidden-source-map:外部,即生成了一个文件,bulit.js.map
错误代码错误原因,但是没有错误位置
不能追踪源代码错误,只能提示到构建后代码的错误位置
eval-source-map:内联
每一个文件都生成对应的source-map,都在eval
错误代码准确信息 和 源代码的错误位置,提示为哈希值
nosources-source-map:外部
错误代码准确信息, 但是没有任何源代码信息
cheap-source-map:外部
错误代码准确信息 和 源代码的错误位置
只能精确到行
cheap-module-source-map:外部
错误代码准确信息 和 源代码的错误位置
module会将loader的source map加入
内联 和 外部的区别:1. 外部生成了文件,内联没有 2. 内联构建速度更快
开发环境:速度快,调试更友好
速度快(eval>inline>cheap>...)
eval-cheap-souce-map
eval-source-map
调试更友好
souce-map
cheap-module-souce-map
cheap-souce-map
--> 推荐 eval-source-map 或 eval-cheap-module-souce-map ,前者调试更友好,后者性能更好
生产环境:源代码要不要隐藏? 调试要不要更友好
内联会让代码体积变大,所以在生产环境不用内联
nosources-source-map 全部隐藏
hidden-source-map 只隐藏源代码,会提示构建后代码错误信息(即webpack打包后)
--> source-map / cheap-module-souce-map
*/
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: ['./src/js/index.js', './src/index.html'],
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
{
// 处理less资源
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
// 处理css资源
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
// 处理图片资源
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
// 关闭es6模块化
esModule: false,
outputPath: 'imgs'
}
},
{
// 处理html中img资源
test: /\.html$/,
loader: 'html-loader'
},
{
// 处理其他资源
exclude: /\.(html|js|css|less|jpg|png|gif)/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'media'
}
}
]
},
plugins: [
// plugins的配置
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development',
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true,
hot: true
},
devtool: 'eval-source-map'
};
外部的样式如下:
内联的样式如下:
追踪到源代码的举例:
/*
主要提示构建速度,如果不处理的话,正常情况下一个文件都要被多个loader过一遍
*/
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 定义nodejs环境变量:决定使用browserslist的哪个环境
process.env.NODE_ENV = 'production';
// 复用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}
];
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
// 在package.json中eslintConfig --> airbnb
test: /\.js$/,
exclude: /node_modules/,
// 优先执行
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
{
// 以下loader只会匹配一个
// 注意:不能有两个配置处理同一种类型文件,例如不能用两个loader处理js文件,
// 要把其中的一个放出来,如上面所示,由上方的eslint-loader执行再由oneOf里面的babel-loader执行
oneOf: [
{
test: /\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']
},
/*
正常来讲,一个文件只能被一个loader处理。
当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
先执行eslint 在执行babel
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: {version: 3},
targets: {
chrome: '60',
firefox: '50'
}
}
]
]
}
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.css'
}),
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
mode: 'production'
};
webpack.config.js
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
/*
缓存:在代码上线时,对资源都要做一个缓存处理,即让用户第二次访问网站的时候不需要太长时间,
速度会变快,但是也会带来一些问题,如果代码产生变化,但浏览器上缓存的资源在强制缓存期间不会访问服务器,
直接读取本地的缓存,所以我们可以给静态资源(js、css)加一个版本号,我们更新资源后,
静态资源的名称改变了,那么这个资源就会更新,我们采取的方法是加上一个哈希值,即下方的
filename: 'js/built.[contenthash:10].js',
babel缓存
cacheDirectory: true
--> 让第二次打包构建速度更快
文件资源缓存:我们推荐使用contenthash,
hash: 每次wepack构建时会生成一个唯一的hash值。
问题: 因为js和css同时使用一个hash值。
如果重新打包,会导致所有缓存失效。(可能我却只改动一个文件)
chunkhash:根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样
问题: js和css的hash值还是一样的
因为css是在js中被引入的,所以同属于一个chunk
contenthash: 根据文件的内容生成hash值。不同文件hash值一定不一样
--> 让代码上线运行缓存更好使用
*/
// 定义nodejs环境变量:决定使用browserslist的哪个环境
process.env.NODE_ENV = 'production';
// 复用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}
];
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.[contenthash:10].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
// 在package.json中eslintConfig --> airbnb
test: /\.js$/,
exclude: /node_modules/,
// 优先执行
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
{
// 以下loader只会匹配一个
// 注意:不能有两个配置处理同一种类型文件
oneOf: [
{
test: /\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']
},
/*
正常来讲,一个文件只能被一个loader处理。
当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
先执行eslint 在执行babel
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
chrome: '60',
firefox: '50'
}
}
]
],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory: true
}
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.[contenthash:10].css'
}),
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
mode: 'production',
devtool: 'source-map'
};
服务器代码server.js
/*
服务器代码
启动服务器指令:
先安装:
npm i nodemon -g
然后输入:
nodemon server.js
或者直接:
node server.js
访问服务器地址:
http://localhost:3000
*/
const express = require('express');
const app = express();
// express.static向外暴露静态资源
// maxAge 资源缓存的最大时间,单位ms,maxAge: 1000 * 3600表示一个小时,
// 表示在浏览器中的静态资源会被强制缓存一个小时
app.use(express.static('build', { maxAge: 1000 * 3600 }));
// 启动服务器,3000表示端口号
app.listen(3000);
index.js
import '../css/index.css';
// es6语法,用args的reduce去统计求和的方法,0表示初始化为0
function sum(...args) {
return args.reduce((p, c) => p + c, 0);
}
// 下面的这个 // eslint-disable-next-line 的意思是忽略下一行的警告,
// 因为在项目上线中,console是不需要的,会影响性能
// eslint-disable-next-line
console.log(sum(1, 2, 3, 4));
如:
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
/*
tree shaking:去除无用代码
前提:1. 必须使用ES6模块化 2. 开启production环境
作用: 减少代码体积
在package.json中配置
"sideEffects": false 所有代码都没有副作用(都可以进行tree shaking)
问题:可能会把css / @babel/polyfill (副作用)文件干掉,
我们可以在package.json中加入下面一行代码:
"sideEffects": ["*.css", "*.less"]
*/
// 定义nodejs环境变量:决定使用browserslist的哪个环境
process.env.NODE_ENV = 'production';
// 复用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}
];
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.[contenthash:10].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
// 在package.json中eslintConfig --> airbnb
test: /\.js$/,
exclude: /node_modules/,
// 优先执行
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
{
// 以下loader只会匹配一个
// 注意:不能有两个配置处理同一种类型文件
oneOf: [
{
test: /\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']
},
/*
正常来讲,一个文件只能被一个loader处理。
当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
先执行eslint 在执行babel
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
chrome: '60',
firefox: '50'
}
}
]
],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory: true
}
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.[contenthash:10].css'
}),
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
mode: 'production',
devtool: 'source-map'
};
{
"name": "text88",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.8.4",
"@babel/polyfill": "^7.8.3",
"@babel/preset-env": "^7.8.4",
"add-asset-html-webpack-plugin": "^3.1.3",
"babel": "^6.23.0",
"babel-loader": "^8.0.6",
"core-js": "^3.6.4",
"css-loader": "^3.6.0",
"eslint": "^6.8.0",
"eslint-config-airbnb-base": "^14.2.0",
"eslint-loader": "^3.0.4",
"eslint-plugin-import": "^2.21.2",
"file-loader": "^5.0.2",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"less": "^3.11.3",
"less-loader": "^5.0.0",
"mini-css-extract-plugin": "^0.9.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"style-loader": "^1.2.1",
"terser-webpack-plugin": "^2.3.5",
"thread-loader": "^2.1.3",
"url-loader": "^3.0.0",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0",
"workbox-webpack-plugin": "^5.0.0"
},
"dependencies": {
"jquery": "^3.4.1"
},
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.1%",
"not dead",
"not op_mini all"
]
},
"eslintConfig": {
"extends": "airbnb-base",
"env": {
"browser": true
}
},
"sideEffects": [
"*.css"
],
"description": ""
}
test.js
export function mul(x, y) {
return x * y;
}
export function count(x, y) {
return x - y;
}
index.js
//只引入test.js中的mul函数
import { mul } from './test';
import '../css/index.css';
function sum(...args) {
return args.reduce((p, c) => p + c, 0);
}
// eslint-disable-next-line
console.log(mul(2, 3));
// eslint-disable-next-line
console.log(sum(1, 2, 3, 4));
共三种方案,我们一般采用第三种方案:
一、
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 单入口
// entry: './src/js/index.js',
entry: {
// 多入口:有几个入口,最终输出就有几个bundle
index: './src/js/index.js',
test: './src/js/test.js'
},
output: {
// [name]:取文件名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
mode: 'production'
};
二、
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 单入口
// entry: './src/js/index.js',
entry: {
index: './src/js/index.js',
test: './src/js/test.js'
},
output: {
// [name]:取文件名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
/*
1. 可以将node_modules中代码单独打包一个chunk最终输出
2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
*/
optimization: {
splitChunks: {
chunks: 'all'
}
},
mode: 'production'
};
三、
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 单入口
entry: './src/js/index.js',
output: {
// [name]:取文件名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
/*
1. 可以将node_modules中代码单独打包一个chunk最终输出
2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
*/
optimization: {
splitChunks: {
chunks: 'all'
}
},
mode: 'production'
};
我们其他文件也希望打包成一个单独的chunk,可以通过书写js代码的形式实现
index.js
function sum(...args) {
return args.reduce((p, c) => p + c, 0);
}
/*
通过js代码,让某个文件被单独打包成一个chunk
import动态导入语法:能将某个文件单独打包
*/
//下面的 /* webpackChunkName: 'test' */ 意思是文件的名字,如果不加的话,会根据id的名字取命名,
import(/* webpackChunkName: 'test' */'./test')
.then(({ mul, count }) => {
// 文件加载成功~
// eslint-disable-next-line
console.log(mul(2, 5));
})
.catch(() => {
// eslint-disable-next-line
console.log('文件加载失败~');
});
// eslint-disable-next-line
console.log(sum(1, 2, 3, 4));
我们没有加入/* webpackChunkName: 'test' */之前
通过加入/* webpackChunkName: 'test' */后
test.js
console.log('test.js文件被加载了~');
// export 表示暴露出来
export function mul(x, y) {
return x * y;
}
export function count(x, y) {
return x - y;
}
index.js
console.log('index.js文件被加载了~');
// import { mul } from './test';
document.getElementById('btn').onclick = function() {
// 懒加载~:当文件需要使用时才加载~
// 预加载 prefetch:会在使用之前,提前加载js文件
// 加入这个即代表开启了预加载:webpackPrefetch: true
// 正常加载可以认为是并行加载(同一时间加载多个文件)
// 预加载 prefetch:等其他资源加载完毕,浏览器空闲了,再偷偷加载资源,
// 但是兼容性较差,只能在高版本的浏览器中使用
import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({ mul }) => {
console.log(mul(4, 5));
});
};
index.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>webpacktitle>
head>
<body>
<h1>hello lazy loadingh1>
<button id="btn">按钮button>
body>
html>
懒加载:
未点击:
点击后:
预加载:
webpack.config.js
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
/*
PWA: 渐进式网络开发应用程序(没有网络也可离线访问,但是一些资源会加载失败,如图片),
淘宝网页采用了这个技术
我们通过 workbox 使用 -->下载 workbox-webpack-plugin ,下载完之后引入,
如上面已经引入,然后在下方的插件里面使用
*/
// 定义nodejs环境变量:决定使用browserslist的哪个环境
process.env.NODE_ENV = 'production';
// 复用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}
];
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.[contenthash:10].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
// 在package.json中eslintConfig --> airbnb
test: /\.js$/,
exclude: /node_modules/,
// 优先执行
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
{
// 以下loader只会匹配一个
// 注意:不能有两个配置处理同一种类型文件
oneOf: [
{
test: /\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']
},
/*
正常来讲,一个文件只能被一个loader处理。
当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
先执行eslint 在执行babel
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
chrome: '60',
firefox: '50'
}
}
]
],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory: true
}
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.[contenthash:10].css'
}),
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
new WorkboxWebpackPlugin.GenerateSW({
/*
1. 帮助serviceworker快速启动
2. 删除旧的 serviceworker
生成一个 serviceworker 配置文件,然后我们通过这个配置文件去注册serviceworker,
我们一般在入口文件中进行配置,此处为index.js
*/
clientsClaim: true,
skipWaiting: true
})
],
mode: 'production',
devtool: 'source-map'
};
index.js
import { mul } from './test';
import '../css/index.css';
function sum(...args) {
return args.reduce((p, c) => p + c, 0);
}
// eslint-disable-next-line
console.log(mul(2, 3));
// eslint-disable-next-line
console.log(sum(1, 2, 3, 4));
/*
1. eslint不认识 window、navigator全局变量
解决:需要修改package.json中eslintConfig配置
"env": {
"browser": true // 支持浏览器端全局变量
}
2. serviceWorker代码必须运行在服务器上
-->一是通过 nodejs
-->二是通过下载包
npm i serve -g
然后输入 serve -s build 启动服务器,将build目录下所有资源作为静态资源暴露出去
*/
// 注册serviceWorker,因为有兼容性问题,还要处理兼容性问题
// 判断serviceWorker是否在navigator属性中,
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
// 绑定事件,等全部资源加载完成去做serviceworker注册
navigator.serviceWorker
.register('/service-worker.js')
// 通过then和catch方法监听是否注册成功
.then(() => {
console.log('sw注册成功了~');
})
.catch(() => {
console.log('sw注册失败了~');
});
});
}
index.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>webpacktitle>
head>
<body>
<h1>hello cacheh1>
body>
html>
输入命令serve -s build后
我们进入这个地址
然后点击Application下的
我们查看注册service Workers 成功缓存的数据
最后
下载:
npm i thread-loader -D
webpack.config.js
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
// 定义nodejs环境变量:决定使用browserslist的哪个环境
process.env.NODE_ENV = 'production';
// 复用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}
];
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.[contenthash:10].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
// 在package.json中eslintConfig --> airbnb
test: /\.js$/,
exclude: /node_modules/,
// 优先执行
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
{
// 以下loader只会匹配一个
// 注意:不能有两个配置处理同一种类型文件
oneOf: [
{
test: /\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']
},
/*
正常来讲,一个文件只能被一个loader处理。
当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
先执行eslint 在执行babel
*/
{
test: /\.js$/,
exclude: /node_modules/,
// 使用多个loader要用数组
use: [
/*
开启多进程打包。
进程启动大概为600ms,进程通信也有开销。
只有工作消耗时间比较长,才需要多进程打包
*/
{
loader: 'thread-loader',
options: {
workers: 2 // 进程2个
}
},
{
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
chrome: '60',
firefox: '50'
}
}
]
],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory: true
}
}
]
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.[contenthash:10].css'
}),
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
new WorkboxWebpackPlugin.GenerateSW({
/*
1. 帮助serviceworker快速启动
2. 删除旧的 serviceworker
生成一个 serviceworker 配置文件~
*/
clientsClaim: true,
skipWaiting: true
})
],
mode: 'production',
devtool: 'source-map'
};
通过externals拒绝将第三方库打包(如果我们在html中通过cdn导入),然后我们通过script的形式将其在html页面中引入
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'production',
externals: {
// 拒绝jQuery被打包进来
jquery: 'jQuery'
}
};
index.js
import $ from 'jquery';
console.log($);
webpack.dll.js
/*
使用dll技术,对某些库(第三方库:jquery、react、vue...)进行单独打包
当你运行 webpack 命令时,默认查找 webpack.config.js 配置文件
需求:需要运行 webpack.dll.js 文件(此处的文件可以任意命名)
--> webpack --config webpack.dll.js
*/
const { resolve } = require('path');
const webpack = require('webpack');
module.exports = {
entry: {
// 最终打包生成的[name] --> jquery
// ['jquery'] --> 要打包的库是jquery
jquery: ['jquery'],
},
output: {
filename: '[name].js',
path: resolve(__dirname, 'dll'),
library: '[name]_[hash]' // 打包的库里面向外暴露出去的内容叫什么名字
},
plugins: [
// 打包生成一个 manifest.json --> 提供和jquery映射
new webpack.DllPlugin({
name: '[name]_[hash]', // 映射库的暴露的内容名称
// 输出文件路径,这个文件会建立起和上方输出的jQuery的映射关系
path: resolve(__dirname, 'dll/manifest.json')
})
],
mode: 'production'
};
webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
// 引入下载的add-asset-html-webpack-plugin,将某个文件打包输出去,
// 并在html中自动引入该资源,就不用手动引入了,
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
// 告诉webpack哪些库不参与打包,同时使用时的名称也得变,因为manifest.json和
// 输出的jQuery建立起了映射关系,所以此时webpack不会把jQuery打包到bulit.js中
new webpack.DllReferencePlugin({
manifest: resolve(__dirname, 'dll/manifest.json')
}),
// 将某个文件打包输出去,并在html中自动引入该资源,就不用手动引入了
new AddAssetHtmlWebpackPlugin({
filepath: resolve(__dirname, 'dll/jquery.js')
})
],
mode: 'production'
};
index.js
// 这样默认会打包jQuery文件,但是我们设置了不打包jQuery,所以此处不打包
import $ from 'jquery';
console.log($);
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
/*
entry: 入口起点,我们一般用第一个和第三个
1. string --> './src/index.js'
单入口
打包形成一个chunk。 输出一个bundle文件。
此时chunk的名称默认是 main
2. array --> ['./src/index.js', './src/add.js']
多入口
所有入口文件最终只会形成一个chunk, 输出出去只有一个bundle文件。
--> 一般不用,只用在HMR功能中让html热更新生效~
3. object
多入口
有几个入口文件就形成几个chunk,输出几个bundle文件
此时chunk的名称是 key
--> 特殊用法
{
// 所有入口文件最终只会形成一个chunk, 输出出去只有一个bundle文件。一般用于dll
index: ['./src/index.js', './src/count.js'],
// 形成一个chunk,输出一个bundle文件。
add: './src/add.js'
}
module是指任意的文件模块,等价于commonjs中的模块
chunks是webpack处理过程中被分组了的modules,如代码分割时一个异步加载的chunk可能包含多个module
Bunldes是指打包出来的
*/
module.exports = {
entry: {
index: ['./src/index.js', './src/count.js'],
add: './src/add.js'
},
output: {
filename: '[name].js',
path: resolve(__dirname, 'build')
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development'
};
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
// 文件名称(指定名称+目录)
filename: 'js/[name].js',
// 输出文件目录(将来所有资源输出的公共目录)
path: resolve(__dirname, 'build'),
// 所有资源引入公共路径前缀,一般用于生产环境 --> 'imgs/a.jpg' --> '/imgs/a.jpg'
publicPath: '/',
// 对非入口chunk的名称进行重命名,不命名的话webpack默认给他命名为一个id值,
// 从0开始,打包入口的chunk默认为main
chunkFilename: 'js/[name]_chunk.js',
// library: '[name]', // 整个库向外暴露的变量名,通常结合dll使用
// libraryTarget: 'window' // 变量名添加到哪个上 browser
// libraryTarget: 'global' // 变量名添加到哪个上 node
// libraryTarget: 'commonjs'
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development'
};
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'js/[name].js',
path: resolve(__dirname, 'build')
},
module: {
// 在rules里写loader的配置
rules: [
// loader的配置
{
// 指定检查某种类型的文件
test: /\.css$/,
// 多个loader用use
use: ['style-loader', 'css-loader']
},
{
test: /\.js$/,
// 排除node_modules下的js文件
exclude: /node_modules/,
// 只检查 src 下的js文件
include: resolve(__dirname, 'src'),
// 优先执行
enforce: 'pre',
// 延后执行
// enforce: 'post',
// 单个loader用loader,还可以在下方加个options指定某些配置选项
loader: 'eslint-loader',
options: {}
},
{
// 以下配置只会生效一个
oneOf: []
}
]
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development'
};
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/[name].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development',
// 解析模块的规则
resolve: {
// 配置解析模块路径别名: 优点简写路径 缺点路径没有提示
alias: {
$css: resolve(__dirname, 'src/css')
},
// 配置省略文件路径的后缀名,但是要注意命名不能相同,例如index1.js和index1.css两个命名相同的话,
// 它默认是按前到后的顺序解析,即它找到index1.css后就不会再去找后面的index1.css
extensions: ['.js', '.json', '.jsx', '.css'],
//加入以上两个配置后在index.js中引入index.css为import '$css/index';原先为../css/index.css
// 告诉 webpack 解析模块是去找哪个目录,
// modules: [resolve(__dirname, '../../node_modules')]
// 这里后面再加上一个 'node_modules' 是为了防止前面找不到(写错),
//因为webpack当前目录找不到默认会一级一级的往上找
modules: [resolve(__dirname, '../../node_modules'), 'node_modules']
}
};
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/[name].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development',
resolve: {
alias: {
$css: resolve(__dirname, 'src/css')
},
extensions: ['.js', '.json', '.jsx', '.css'],
modules: [resolve(__dirname, '../../node_modules'), 'node_modules']
},
// devServer用于开发环境
devServer: {
// 运行代码的目录
contentBase: resolve(__dirname, 'build'),
// 监视 contentBase 目录下的所有文件,一旦文件变化就会 reload(重载)
watchContentBase: true,
watchOptions: {
// 忽略node_modules文件
ignored: /node_modules/
},
// 启动gzip压缩
compress: true,
// 端口号
port: 5000,
// 域名
host: 'localhost',
// 自动打开浏览器
open: true,
// 开启HMR功能
hot: true,
// 不要显示启动服务器日志信息
clientLogLevel: 'none',
// 除了一些基本启动信息以外,其他内容都不要显示
quiet: true,
// 如果出错了,不要全屏提示~
overlay: false,
// 服务器代理 --> 解决开发环境跨域问题(浏览器和服务器之间存在跨域问题,比如域名、
// 协议、端口号不一样就会产生跨域,服务器与服务器之间没有跨域)
// 代码通过代理服务器运行,浏览器和代理服务器之间没有跨域问题,浏览器把请求发送到代理服务器上,
// 代理服务器代替转发到另一个服务器上,因为服务器与服务器之间没有跨域问题,所以请求成功,
// 代理服务器再把接收到的响应响应给浏览器,从而解决开发环境下的跨域问题
proxy: {
// 一旦devServer(5000,上面设置的)服务器接受到 /api/xxx 的请求,就会把请求转发到另外一个服务器(3000)
'/api': {
target: 'http://localhost:3000',
// 发送请求时,请求路径重写:将 /api/xxx --> /xxx (去掉/api)
pathRewrite: {
'^/api': ''
}
}
}
}
};
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin')
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build'),
chunkFilename: 'js/[name].[contenthash:10]_chunk.js'
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [new HtmlWebpackPlugin()],
mode: 'production',
resolve: {
alias: {
$css: resolve(__dirname, 'src/css')
},
extensions: ['.js', '.json', '.jsx', '.css'],
modules: [resolve(__dirname, '../../node_modules'), 'node_modules']
},
optimization: {
// splitChunks用来做代码分割
splitChunks: {
chunks: 'all'
// 默认值,可以不写~
/* minSize: 30 * 1024, // 分割的chunk最小为30kb,即小于30kb就不分割
maxSiza: 0, // 最大没有限制
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: {
// 要提取的chunk最少被引用2次
minChunks: 2,
// 优先级
priority: -20,
// 如果当前要打包的模块,和之前已经被提取的模块是同一个,就会复用,而不是重新打包模块
reuseExistingChunk: true
}
}*/
},
// 将当前模块的记录其他模块的hash单独打包为一个文件 runtime
// 解决:修改a文件导致b文件的contenthash变化,即当a.js变化时打包的main.js(主文件)也会变化,
// 因为main.js要引入a.js文件,为了引入文件把哈希值也引入进来了
// 当改动a.js后a.js的哈希值变化了就会导致main.js的哈希值也会改变就会导致有两个main.js,就会导致缓存失效
runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}`
},
minimizer: [
// 配置生产环境的压缩方案:js和css
new TerserWebpackPlugin({
// 开启缓存
cache: true,
// 开启多进程打包
parallel: true,
// 启动source-map
sourceMap: true
})
]
}
};
a.js
export function add(x, y) {
return x + y;
}
index.js
// 引入a.js成功的话就提取add方法打印在控制台,/* webpackChunkName: 'a' */
// 表示对提取的文件进行重命名,用这个语法会单独打包为一个js文件
import(/* webpackChunkName: 'a' */'./a.js').then(({ add }) => {
console.log(add(1, 2));
});
改变a.js后
解决,
//webpack4
const { resolve } = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: '[name].js',
path: resolve(__dirname, 'build')
},
mode: 'production'
};
//webpack5
module.exports = {
mode: 'production'
};
此版本重点关注以下内容:
npm i webpack@next webpack-cli -D
自动删除 Node.js Polyfills
早期,webpack 的目标是允许在浏览器中运行大多数 node.js 模块,但是模块格局发生了变化,许多模块用途现在主要是为前端目的而编写的。webpack <= 4 附带了许多 node.js 核心模块的 polyfill,一旦模块使用任何核心模块(即 crypto 模块),这些模块就会自动应用。
尽管这使使用为 node.js 编写的模块变得容易,但它会将这些巨大的 polyfill 添加到包中。在许多情况下,这些 polyfill 是不必要的。
webpack 5 会自动停止填充这些核心模块,并专注于与前端兼容的模块。
迁移:
添加了用于长期缓存的新算法。在生产模式下默认情况下启用这些功能。
chunkIds: "deterministic", moduleIds: "deterministic"
你可以不用使用 import(/* webpackChunkName: "name" */ "module")
在开发环境来为 chunk 命名,生产环境还是有必要的
webpack 内部有 chunk 命名规则,不再是以 id(0, 1, 2)命名了
// inner.js
export const a = 1;
export const b = 2;
// module.js
import * as inner from './inner';
export { inner };
// user.js
import * as module from './module';
console.log(module.inner.a);
在生产环境中, inner 模块暴露的 b
会被删除
import { something } from './something';
function usingSomething() {
return something;
}
export function test() {
return usingSomething();
}
当设置了"sideEffects": false
时,一旦发现test
方法没有使用,不但删除test
,还会删除"./something"
webpack 4 默认只能输出 ES5 代码
webpack 5 开始新增一个属性 output.ecmaVersion, 可以生成 ES5 和 ES6 / ES2015 代码.
如:output.ecmaVersion: 2015
// webpack4
minSize: 30000;
// webpack5
minSize: {
javascript: 30000,
style: 50000,
}
// 配置缓存
cache: {
// 磁盘存储
type: "filesystem",
buildDependencies: {
// 当配置修改时,缓存失效
config: [__filename]
}
}
缓存将存储到 node_modules/.cache/webpack
之前 webpack 总是在第一次构建时输出全部文件,但是监视重新构建时会只更新修改的文件。
此次更新在第一次构建时会找到输出文件看是否有变化,从而决定要不要输出全部文件。
entry: "./src/index.js
output.path: path.resolve(__dirname, "dist")
output.filename: "[name].js"
https://github.com/webpack/changelog-v5
至此,我们的webpack的学习
就讲解完成了,源码素材可以通过关注我的微信公众号 我爱学习呀嘻嘻
,回复关键字webpack源码素材
进行获取哦。