💥此MD/PDF/HTML文档由 @竹梦者也 编辑制作,不可贩卖❌。仅供学习交流使用,下载后切勿随意传播。转载麻烦加上出处~
📌欢迎在留言区提供修改建议~
💌本文内容和代码来自于
tianyu
老师的webpack
教程✨本笔记所有相关配置已兼容webpack-5.38.1版本,请根据你的版本
webpack -v
正确食用。
✅2021.7.13 @竹梦者也(https://www.zjgsuzjx.top)
一、webpack4.0一、基本概念1. 铺垫2. 含义3. 核心概念4. 理解Loader5. 理解Plugins二、简单使用过程1. 安装2. 项目初始化3. 原生打包JS和JSON三、使用webpack配置文件四、使用工具1. 打包less资源2. JS语法检查3. JS语法转换4. JS兼容性处理# 第一种方法# 第二种方法5. 打包样式文件中的图片资源6. 打包html文件7. 打包html中图片资源8. 打包媒体资源9. 自动编译打包运行10. 热模替换功能11. devtool12. 准备生产环境13. 清除打包文件目录14. 提取css成单独文件15. 添加css兼容16. 压缩css17. 压缩html五、总结二、webpack5.0新特性后续会更新
grunt
->gulp
->webpack
(主流)
源代码:程序员写的没有经过任何的加工的代码 源代码最好经过层层的加工处理
src
----源代码---程序员写的没有经过任何的加工的代码--------生的鸡蛋、生的大米。
dist/build/built
----加工之后的代码---经过层层的加工处理的代码----------蛋炒饭
构建:将程序写的源代码,经过编译、压缩、语法检查、兼容性处理、生成浏览器可以高效、稳定运行的代码
Webpack
是一个模块打包器(bundler
)。Webpack
看来, 前端的所有资源文件(js
/json
/css
/img
/less
/...)都会作为模块处理Entry
:入口起点(entry point)指示 webpack
应该使用哪个模块,来作为构建其内部依赖图的开始。Output:output
属性告诉 webpack
在哪里输出它所创建的 bundles,以及如何命名这些文件,默认值为 ./dist
。Loader
:loader
让 webpack
能够去处理那些非 JavaScript
文件(webpack
自身只能解析 JavaScript)。Plugins
:插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等。Mode
:模式,有生产模式production和开发模式developmentWebpack
本身只能加载JS/JSON模块,如果要加载其他类型的文件(模块),就需要使用对应的loader
进行转换/加载Loader
本身也是运行在 node.js 环境中的 JavaScript 模块loader
一般以 xxx-loader
的方式命名,xxx 代表了这个 loader
要做的转换功能,比如 json-loader
。loader
不能完成的功能。webpack
的配置信息 plugins
选项中指定。npm i webpack webpack-cli -g
//全局安装,作为指令使用npm i webpack webpack-cli -D
//本地安装,作为本地依赖使用生成package.json
文件
如:
1{
2 "name": "webpack_test",
3 "version": "1.0.0"
4}
举例
创建js
文件:
src/js/index.js
x1/*
2注意!!!
3该index.js不同于学习链块化时,那个用于汇总js的文件。
4模块化技术的index.js只用于汇总各个js模块。
5该index.js 是webpack的【入口文件】
6该文件可以用于汇总:js、css、图片、音频、视频
7*/
8import {sum} from './module1'
9import {sub} from './module2'
10import module3 from './module3'
11import a from '../json/test.json'
12
13console.log(sum(1, 2))
14console.log(sub(3, 4))
15console.log(module3.mul(5, 6))
16console.log(module3.div(10, 5))
17
18console.log(a, typeof a)
19
20// webpack只管翻译es6的模块化语法变为浏览器认识的,但是不会处理其他语法
21setTimeout(() => {
22 console.log('hello')
23}, 1000)
src/js/module1.js
src/js/module2.js
src/js/module3.js
创建json
文件:
src/json/test.json
创建主页面:
src/index.html
运行指令:
开发配置指令:webpack ./src/js/index.js -o dist/js --mode development
webpack
能够编译打包js
和json
文件,并且能将es6的模块化语法转换成浏览器能识别的语法生产配置指令:webpack ./src/js/index.js -o dist/js --mode production
注意:我是webpack5.38.1, 与4的区别是必须要求目录前面加上
./
,且默认文件名为main.js
结论:
webpack
能够编译打包js
和json
文件缺点:
css
、img
等文件js
的es6基本语法转化为es5以下语法改善:
使用webpack
配置文件解决,自定义功能
官方中文文档:https://webpack.docschina.org/concepts/
目的:在项目根目录定义配置文件,通过自定义配置文件,还原以上功能
文件名称:webpack.config.js
文件内容:
xxxxxxxxxx
151const {resolve} = require('path'); //node内置核心模块,用来设置路径。
2module.exports = {
3 entry: './src/js/index.js', // 入口文件配置(简写)
4 /*完整写法:
5 entry:{
6 main:'./src/js/app.js'
7 }
8 */
9 output: { // 输出配置
10 filename: './js/index.js', // 输出文件名
11 path: resolve(__dirname, 'build') //输出文件路径配置
12 },
13 // mode: 'development' //开发环境(二选一)
14 mode: 'production' //生产环境(二选一)
15};
运行指令: webpack
概述:less文件webpack不能解析,需要借助loader编译解析
创建less文件:
src/less/test1.less
src/less/test2.less
在index.js文件引入:
xxxxxxxxxx
11import '../less/test.less'
安装loader:
npm install css-loader style-loader less-loader less -D
配置loader:
xxxxxxxxxx
151module: {
2 // 所有的loader都要再module对象中的rules属性中
3 // rules是一个数组,数组中的每一个对象就是一个loader
4 rules: [
5 {
6 test: /\.less$/i, // 匹配所有的less文件
7 use: [
8 // 使用lessloader,将less编译为CSS
9 'style-loader',
10 'css-loader',
11 'less-loader',
12 ],
13 },
14 ],
15}
注意:上端代码加在
module.exports
里。
运行指令:webpack
概述:对js
基本语法错误/隐患,进行提前检查
安装loader:npm install eslint-loader eslint -D
注意:现在已经被弃用了
在:eslint.org网站 -> userGuide -> Configuring ESLint 查看如何配置
在:eslint.org网站 -> userGuide -> Rules 查看所有规则
官方中文文档:https://cn.eslint.org/
配置loader:
xxxxxxxxxx
81{
2 test: /\.js$/, //只检测js文件
3 exclude: /node_modules/, //排除node_modules文件夹
4 enforce: "pre", //提前加载使用
5 use: { //使用eslint-loader解析
6 loader: "eslint-loader"
7 }
8}
需要加在
module
的rules
里。
修改package.json:
x
1"eslintConfig": {
2 "parserOptions": {
3 "ecmaVersion": 6,
4 "sourceType": "module"
5 },
6 "env": { // 设置环境
7 "browser": true, // 支持浏览器环境: 能够使用window上的全局变量
8 "node": true, // 支持服务器环境: 能够使用node上global的全局变量
9 "es6": true // 支持es6新语法
10 },
11 "globals": { // 声明使用的全局变量, 这样即使没有定义也不会报错了
12 "$": "readonly" // $ 只读变量
13 },
14 "rules": { // eslint检查的规则 0 忽略 1 警告 2 错误
15 "no-console": 0, // 不检查console
16 "eqeqeq": 2, // 用==而不用===就报错
17 "no-alert": 2 // 不能使用alert
18 },
19 "extends": "eslint:recommended" // 使用eslint推荐的默认规则 https://cn.eslint.org/docs/rules/
20}
注意:JSON不能有注释!记得删掉
运行指令:webpack
概述:将浏览器不能识别的新语法转换成原来识别的旧语法,做浏览器兼容性处理
安装loader:npm install babel-loader @babel/core @babel/preset-env --save-dev
配置loader:
xxxxxxxxxx
101{
2 test: /\.js$/,
3 exclude: /node_modules/,
4 use: {
5 loader: "babel-loader",
6 options: {
7 presets: ['@babel/preset-env']
8 }
9 }
10}
要加在
module
的rules
里。
运行指令:webpack
缺点:不能转换高级语法比如Promise,也不能兼容IE旧版本浏览器。
使用经典的polyfill
安装:npm install @babel/polyfill
使用:
在index.js
(入口JS文件)加入下面代码,最好放在最上面
xxxxxxxxxx
11import '@babel/polyfill'; // 包含ES6的高级语法的转换
优点:解决babel
只能转换部分低级语法的问题(如:let
/const
/解构赋值...),引入polyfill
可以转换高级语法(如:Promise
)
缺点:将所有高级语法都进行了转换,但实际上可能只使用一部分。所以导致文件变得很大很大。
解决:需要按需加载(使用了什么高级语法,就转换什么,而其他的不转换)
借助按需引入core-js
按需引入。
安装:npm install core-js
配置loader:
xxxxxxxxxx
241// js语法转换(es6->es5)
2{
3 test: /\.js$/,
4 exclude: /(node_modules)/,
5 use: {
6 loader: 'babel-loader',
7 options: {
8 presets: [
9 [
10 '@babel/preset-env',
11 {
12 useBuiltIns: 'usage', // 按需引入需要使用polyfill
13 corejs: {version: 3}, // 解决不能找到core-js的问题
14 targets: { // 指定兼容性处理哪些浏览器
15 "chrome": "58",
16 "ie": "9",
17 }
18 }
19 ]
20 ],
21 cacheDirectory: true, // 开启babel缓存
22 }
23 }
24}
要加在
module
的rules
里。补充:将浏览器兼容性版本调高可以减小压缩后的文件大小。
概述:图片文件webpack不能解析,需要借助loader编译解析
添加2张图片:
src/images/vue.png
src/images/react.jpg
Base64编码适合于8kb以下图片。
引入图片:在less或css文件中通过背景图的方式引入图片
安装loader:
npm install file-loader url-loader -D
补充:
url-loader
是对象file-loader
的上层封装,使用时需配合file-loader
使用。
配置loader:
xxxxxxxxxx
121{
2 test: /\.(png|jpg|gif)$/,
3 use: {
4 loader: 'url-loader',
5 options: {
6 limit: 8192, // 8kb --> 8kb以下的图片会base64处理
7 outputPath: 'images', // 决定文件本地输出路径
8 publicPath: '../build/images', // 决定图片的url路径
9 name: '[hash:8].[ext]' // 修改文件名称 [hash:8] hash值取8位 [ext] 文件扩展名
10 }
11 }
12}
运行指令:webpack
概述:html
文件webpack
不能解析,需要借助插件编译解析
添加html文件:src/index.html
注意不要在html中引入任何css和js文件
安装插件:
npm install html-webpack-plugin -D
配置Plugins:
在webpack.config.js
中引入插件(插件都需要手动引入,而loader
会自动加载)
xxxxxxxxxx
11const HtmlWebpackPlugin = require('html-webpack-plugin')
以下代码与module
平行关系:
xxxxxxxxxx
61// 配置插件
2plugins: [
3 new HtmlWebpackPlugin({
4 template: './src/index.html', // 以当前文件为模板创建新的HtML(1. 结构和原来一样 2. 会自动引入打包的资源)
5 }),
6]
运行指令:webpack
概述:html
中的图片url-loader
没法处理,它只能处理js
中引入的图片 / 样式中图片,不能处理html
中img
标签,需要引入其他html-loader
处理。
添加图片:在src/index.html
添加两个img
标签
安装loader:
npm install html-loader -D
配置loader:
xxxxxxxxxx
121{
2 test: /\.(html)$/,
3 use: [
4 {
5 loader: 'html-loader',
6 options: {
7 // 不使用es模块,防止图片地址错误
8 esModule: false
9 }
10 }
11 ]
12}
概述:其他资源webpack
不能解析,需要借助loader
编译解析
添加字体文件(举例):src/media/iconfont.ttf
(以阿里图标为例)
修改样式:
xxxxxxxxxx
251@font-face {
2 font-family: "iconfont"; /* Project id */
3 // 统一把字体图标放到media下面
4 src: url('../media/iconfont.ttf?t=1626110174654') format('truetype');
5}
6
7.iconfont {
8 font-family: "iconfont" !important;
9 font-size: 16px;
10 font-style: normal;
11 font-smoothing: antialiased;
12 osx-font-smoothing: grayscale;
13}
14
15.icon-cangchucangku:before {
16 content: "\e98c";
17}
18
19.icon-bingtutubiao:before {
20 content: "\e98d";
21}
22
23.icon-chayan:before {
24 content: "\e98e";
25}
在index.js引入:
xxxxxxxxxx
11import '../css/iconfont.less'
html里添加字体:
xxxxxxxxxx
11<span class="iconfont icon-bingtutubiao"></span>
配置loader:
xxxxxxxxxx
81{
2 test: /\.(eot|svg|woff|woff2|ttf|mp3|mp4|avi)$/, // 处理其他资源
3 loader: 'file-loader',
4 options: {
5 outputPath: 'media',
6 name: '[hash:8].[ext]'
7 }
8}
运行指令:webpack
概念:能够将所有打包后的文件放在内存里,并且自动配置并打开了一个服务器,能够实现实时刷新页面。不会在本地输出文件。
详细配置见官网:指南 -> 开发环境 -> 使用webpack-dev-server
自动刷新:live-reload 是webpack-dev-server 自带的
安装loader:
npm install webpack-dev-server -D
配置对象:
61// 配置自动化编译
2devServer: {
3 open:true, // 自动打开浏览器
4 compress:true, // 启动gzip压缩
5 port:3000 // 端口号
6}
注意这段代码和
module
是平行关系。
修改url-loader部分配置:
xxxxxxxxxx
1loader: 'url-loader',
2options: {
3 limit: 8192,
4 outputPath: 'images',
5 publicPath: 'images/', // 修改文件途径,因为构建工具以build为根目录,不用再找build了
6 name: '[hash:8].[ext]'
7}
修改package.json:
xxxxxxxxxx
1"scripts": {
2 "start": "webpack serve"
3 }
运行指令:npm start
注意:
webpack-dev-server
指令才能启动devServer
配置,然后配置到package.json
中才行
概述:热模块替换(HMR
)是webpack提供的最有用的功能之一。它允许在运行时更新所有类型的模块,而无需完全刷新(只更新变化的模块,不变的模块不更新)。
详细配置见官网:指南 -> 模块热替换
修改devServer配置:
xxxxxxxxxx
1devServer: {
2 open:true,
3 compress:true,
4 port:3000,
5 hot:true // 开启热模替换功能 HMR
6}
问题:html
文件无法自动更新了,需要增加一个入口
11entry: ['./src/js/index.js','./src/index.html']
概述: 一种将压缩/编译文件中的代码映射回源文件中的原始位置的技术,让我们调试代码不在困难
简单来讲就是出现错误时将定位到源代码的行号,而不是打包后的行号。
详细配置见官网:配置 -> devtool
介绍:
推荐使用:
11devtool: 'eval-cheap-module-source-map' // 开发环境
xxxxxxxxxx
1devtool: 'cheap-module-source-map' // 生产环境
概念:之前都是基于开发环境下的调试。在项目上线后就是生产环境了,所以会有较大的区别,需要单独为生产环境配置。
第一步:
创建文件夹config
,将webpack.config.js
复制两份。
./config/webpack.dev.js
./config/webpack.prod.js
之后可以删除根目录下的webpack.config.js
。
第二步:
修改webpack.prod.js
配置,删除webpack-dev-server
配置。
修改output
:
xxxxxxxxxx
1output: {
2 filename: './js/index.js',
3 path: resolve(__dirname, '../build'), // 路径要翻出去
4 publicPath: '/' // 所有输出资源在引入时的公共路径,若loader中也指定了publicPath,会以loader的为准。
5}
修改mode
:
11mode: 'production'
修改module
中的url-loader
:
xxxxxxxxxx
1{
2 test: /\.(png|jpg|gif)$/,
3 use: {
4 loader: 'url-loader',
5 options: {
6 limit: 8192,
7 outputPath: 'images',
8 publicPath: '/images/', // 重写publicPath,需要在路径前面加上 /
9 name: '[hash:8].[ext]'
10 }
11 }
12}
修改devtool
:
11devtool: 'cheap-module-source-map'
第三步:
修改package.json
的脚本指令。
x
1"scripts": {
2 "start": "webpack serve --config ./config/webpack.dev.js",
3 "dev": "webpack server --config ./config/webpack.dev.js",
4 "build": "webpack --config ./config/webpack.prod.js"
5}
备注:
start
和dev
的功能是一样的,部分企业会用后者。
第四步:
根据不同环境执行不同的指令。
npm start
或 npm run dev
npm run build
第五步:
注意: 生产环境代码需要部署到服务器上才能运行 (serve这个库能帮助我们快速搭建一个静态资源服务器)
安装:npm i serve -g
执行:serve -s build -p 5000
概述:每次打包生成了文件,都需要手动删除,引入插件帮助我们自动删除上一次的文件
安装插件:
npm install clean-webpack-plugin -D
引入插件:
11const { CleanWebpackPlugin } = require('clean-webpack-plugin'); // 注意要解构赋值!!!
上面代码放在
webpack.prod.js
最上方的引入部分
配置插件:
xxxxxxxxxx
1plugins: [
2 // ...
3 new CleanWebpackPlugin()
4]
运行指令:npm run build
安装插件:
npm install mini-css-extract-plugin -D
引入插件:
11const MiniCssExtractPlugin = require("mini-css-extract-plugin");
上面代码放在
webpack.prod.js
最上方的引入部分
配置loader:
xxxxxxxxxx
1{
2 test: /\.less$/i, // 匹配所有的less文件
3 use: [
4 MiniCssExtractPlugin.loader, // 将原来的替换掉
5 'css-loader',
6 'less-loader',
7 ],
8}
配置插件:
1new MiniCssExtractPlugin({
2 filename: "css/[name].css",
3})
运行指令:
npm run build
注意:记住直接打开
build
里的index.html
会报错,因为路径问题。所以要利用serve -s build -p 5000
来打开
不兼容5.0+,暂时找不到解决方法。
安装插件:
npm install optimize-css-assets-webpack-plugin -D
引入插件:
11const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
配置插件:
111new OptimizeCssAssetsPlugin({
2 cssProcessorPluginOptions: {
3 preset: ['default', { discardComments: { removeAll: true } }],
4 },
5 cssProcessorOptions: { // 解决没有source map问题
6 map: {
7 inline: false,
8 annotation: true,
9 }
10 }
11}),
运行指令:npm run build
修改插件配置:
151new HtmlWebpackPlugin({
2 template: './src/index.html',
3 minify: {
4 removeComments: true, // 移除注释
5 collapseWhitespace: true, // 折叠所有空白
6 removeRedundantAttributes: true, // 移除无用的标签
7 useShortDoctype: true, // 使用短的文档声明
8 removeEmptyAttributes: true, // 移除空标签
9 removeStyleLinkTypeAttributes: true, // 移除rel="stylesheet"
10 keepClosingSlash: true, // 自结束
11 minifyJS: true,
12 minifyCSS: true,
13 minifyURLs: true,
14 }
15})
运行指令:npm run build
开发使用
start
,产品上线测试使用build
和serve
。