Webpack
一 、什么是webpack
WebPack是一个现代JS应用程序的静态模块打包器(module bundler)
模块(模块化开发,可以提高开发效率,避免重复造轮子)
打包(将各个模块,按照一定的规则组装起来)
官网:https://webpack.js.org/ 中文网 https://webpack.docschina.org/
特点:功能强大(打包,构建,发布web服务),学习成本高
二、什么是前端工程化
前端工程化是依据业务特点,将前端开发的规范、流程、技术、工具、经验等形成规范并建立成一种标准的体系
三、构建工具
构建工具的主要功能就是实现自动化处理,例如对代码进行检查、预编译、合并、压缩;生成雪碧图、sourceMap、版本管理;运行单元测试、监控等,当然有的工具还提供模块化、组件化的开发流程功能。
网上各类的构建工具非常多,有家喻户晓的 Webpack、Gulp、 Grunt,也有各大公司团队开源的构建工具,这里通过 Github 的 Star 数量来简单的对比下各个工具的流行度
四、安装webpack
-
初始化包描述文件
npm init -y
-
全局安装webpack
npm i webpack webpack-cli -g
-
将webpack添加到package.json的依赖
npm i webpack webpack-cli -D
-
运行命令
webpack
-
创建以下文件夹
- public文件夹-index.html文件
- src文件夹 – main.js 和assets文件夹
public和assets的区别?
assets会打包,public不会打包,public任何人都可以访问
-
运行命令
1.开发环境,默认生成dist文件夹以及下面的main.js文件
webpack ./src/main.js -o ./dist --mode=development
2.生产环境,默认生成dist文件夹以及下面的main.js文件
webpack ./src/main.js -o ./dist --mode=production
由于每次运行都需要写这么长的命令,因此把他配置到package.json文件夹
"dev":"webpack" 这个是配置一个webpack.config.js的配置文件
-
webpack.config.js配置文件
const path=require("path") module.exports = { // 入口 // 相对路径和绝对路径都行 entry: path.join(__dirname, "./src/main.js"), // 输出 output: { // path: 文件输出目录,必须是绝对路径 // path.resolve()方法返回一个绝对路径 // __dirname 当前文件的文件夹绝对路径 path: path.join(__dirname, "./dist"), // filename: 输出文件名 filename: "main.js" }, // 加载器 module: {}, // 插件 plugins: [], // 模式 mode: "development",// 开发模式 }
运行的时候,直接敲 npm run dev
五大核心概念
- entry(入口)
指示 Webpack 从哪个文件开始打包
- output(输出)
指示 Webpack 打包完的文件输出到哪里去,如何命名等
- loader(加载器)
webpack 本身只能处理 js、json 等资源,其他资源需要借助 loader,Webpack 才能解析
- plugins(插件)
扩展 Webpack 的功能
- mode(模式)
主要由两种模式:
- 开发模式:development
- 生产模式:production
六、loader
Webpack 本身是不能识别样式资源的,所以我们需要借助 Loader 来帮助 Webpack 解析样式资源
我们找 Loader 都应该去官方文档中找到对应的 Loader,然后使用
官方文档找不到的话,可以从社区 Github 中搜索查询
Webpack 官方 Loader 文档
七、css 资源和sass资源
-
下载包
sass
npm i sass-loader sass -D
css
npm i css-loader style-loader -D
-
功能介绍
- css-loader:负责将 Css 文件编译成 Webpack 能识别的模块
- style-loader:会动态创建一个 Style 标签,里面放置 Webpack 中 Css 模块内容
此时样式就会以 Style 标签的形式在页面上生效 - sass-loader:负责将 Sass 文件编译成 css 文件
- sass:sass-loader 依赖 sass 进行编译
const path = require("path"); module.exports = { entry: "./src/main.js", output: { path: path.resolve(__dirname, "dist"), filename: "main.js", }, module: { rules: [ { // 用来匹配 .css 结尾的文件 test: /\.css$/, // use 数组里面 Loader 执行顺序是从右到左 use: ["style-loader", "css-loader"], }, { test: /\.s[a|c]ss$/, use: ["style-loader", "css-loader", "sass-loader"], }, ], }, plugins: [], mode: "development", };
-
添加 Css 资源
-
src/assets/css/index.css
-
src/main.js
import "./assets/css/index.css" import "./assets/sass/index.scss"
-
public/index.html
-
八、Html 资源
配置以下内容,就不需要到index.html文件下面导入js文件,会自动导入
-
下载
npm i html-webpack-plugin -D
-
配置webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin") plugins: [ new HtmlWebpackPlugin({ inject: "body", template: path.join(__dirname, "./public/index.html") })
-
修改 index.html
去掉引入的 js 文件,因为 HtmlWebpackPlugin 会自动引入
九、devServer
文件内容改变,自动更新浏览器模块,并且自动打开页面
-
安装
npm i webpack-dev-server -D
-
配置在webpack.config.js文件中
// 开发服务器 devServer: { host: "localhost", // 启动服务器域名 port: "3000", // 启动服务器端口号 open: true, // 是否自动打开浏览器, compress:true, //开启gzip hot: true, // 开启HMR功能(只能用于开发环境,生产环境不需要了 },
-
启动
"serve": "webpack-dev-server"
十、proxy代理
proxy: {
'/api': {
target: 'http://127.0.0.1:8888',//目标代理接口
pathRewrite: {
'^/api': ''
}//把请求路径中的api替换成""
}
十一、图片资源
webpack.config.js文件的module模块下面的rules
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
}
}
generator: {
// 将图片文件输出到 static/imgs 目录中
// 将图片文件命名 [hash:8][ext][query]
// [hash:8]: hash值取8位
// [ext]: 使用之前的文件扩展名
// [query]: 添加之前的query参数
filename: "static/imgs/[hash:8][ext][query]",
},
十二、自动清空上次打包资源
webpack.config.js文件
output: {
path: path.resolve(__dirname, "dist"),
filename: "static/js/main.js",
clean: true, // 自动将上次打包目录资源清空
},
十三、处理字体图标资源
1.打开阿里巴巴矢量图标库
2。选择想要的图标添加到购物车,统一下载到本地
●src/main.js
import "./css/iconfont.css";
-
public/index.html
<i class="iconfont icon-arrow-down"></i> <i class="iconfont icon-ashbin"></i> <i class="iconfont icon-browse"></i>
-
配置webpack.config.js文件
{ test: /\.(ttf|woff2?)$/, type: "asset/resource", generator: { filename: "static/media/[hash:8][ext][query]", }, },
type: "asset/resource"和type: "asset"的区别:
- type: “asset/resource” 相当于file-loader, 将文件转化成 Webpack 能识别的资源,其他不做处理
- type: “asset” 相当于url-loader, 将文件转化成 Webpack 能识别的资源,同时小于某个大小的资源会处理成 data URI 形式
视频音频也可以使用以上配置,只需要修改 test: /.(ttf|woff2?|map4|map3|avi)$/
十四、tree shaking(打包优化)
// webpack的优化1 tree shaking在webpack的配置下,添加一个 optimization的usedExports
// webpack的优化2 splitChunk分包
optimization: {
usedExports: true
}
在production 模式下不用在webpack.config.js中配置
官方有标准的说法:Tree-shaking的本质是消除无用的js代码。无用代码消除在广泛存在于传统的编程语言编译器中,编译器可以判断出某些代码根本不影响输出,然后消除这些代码,这个称之为DCE(dead code elimination)
十五、Eslint
使用 Eslint,关键是写 Eslint 配置文件,里面写上各种 rules 规则,将来运行 Eslint 时就会以写的规则对代码进行检查,完成 Eslint,检测代码格式无误后,在由 Babel 做代码兼容性处理
1.配置文件
配置文件由很多种写法:
●.eslintrc.*:新建文件,位于项目根目录
○.eslintrc
○.eslintrc.js
○.eslintrc.json
○区别在于配置格式不一样
●package.json 中 eslintConfig:不需要创建文件,在原有文件基础上写
ESLint 会查找和自动读取它们,所以以上配置文件只需要存在一个即可
2.具体配置
我们以 .eslintrc.js 配置文件为例:
module.exports = {
// 继承 Eslint 规则
extends: ["eslint:recommended"],
env: {
node: true, // 启用node中全局变量
browser: true, // 启用浏览器中全局变量
},
parserOptions: {
ecmaVersion: 6,
sourceType: "module",
},
rules: {
"no-var": 2, // 不能使用 var 定义变量
"no-console":0
},
};
2.rules 具体规则
●"off" 或 0 - 关闭规则
●"warn" 或 1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出)
●"error" 或 2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)
rules: {
semi: "error", // 禁止使用分号
'array-callback-return': 'warn', // 强制数组方法的回调函数中有 return 语句,否则警告
'default-case': [
'warn', // 要求 switch 语句中有 default 分支,否则警告
{ commentPattern: '^no default$' } // 允许在最后注释 no default, 就不会有警告了
],
eqeqeq: [
'warn', // 强制使用 === 和 !==,否则警告
'smart' // https://eslint.bootcss.com/docs/rules/eqeqeq#smart 除了少数情况下不会有警告
],
}
更多规则详见:规则文档
3.extends 继承
开发中一点点写 rules 规则太费劲了,所以有更好的办法,继承现有的规则。
现有以下较为有名的规则:
●Eslint 官方的规则:eslint:recommended
●Vue Cli 官方的规则:plugin:vue/essential
●React Cli 官方的规则:react-app
// 例如在React项目中,我们可以这样写配置
module.exports = {
extends: ["react-app"],
rules: {
// 我们的规则会覆盖掉react-app的规则
// 所以想要修改规则直接改就是了
eqeqeq: ["warn", "smart"],
},
};
- 在 Webpack 中使用
1下载包
npm i eslint-webpack-plugin eslint -D
2 定义 Eslint 配置文件
●.eslintrc.js
module.exports = {
// 继承 Eslint 规则
extends: ["eslint:recommended"],
env: {
node: true, // 启用node中全局变量
browser: true, // 启用浏览器中全局变量
},
parserOptions: {
ecmaVersion: 6,
sourceType: "module",
},
rules: {
"no-var": 2, // 不能使用 var 定义变量
},
};
3修改 js 文件代码
●main.js
var result1 = count(2, 1);
console.log(result1);
var result2 = sum(1, 2, 3, 4);
console.log(result2);
4.配置
●webpack.config.js
const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
module.exports = {
plugins: [
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "src"),
}),
],
mode: "development",
};
●.eslintignore
# 忽略dist目录下所有文件
dist
Babel
JavaScript 编译器。
主要用于将 ES6 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中
1.配置文件
配置文件由很多种写法:
●babel.config.*:新建文件,位于项目根目录 babel.config.js babel.config.json
●.babelrc.*:新建文件,位于项目根目录 .babelrc .babelrc.js .babelrc.json
●package.json 中 babel:不需要创建文件,在原有文件基础上写 Babel 会查找和自动读取它们,所以以上配置文件只需要存在一个即可
2.具体配置
我们以 babel.config.js 配置文件为例:
module.exports = {
// 预设
presets: [],
};
1.presets 预设
简单理解:就是一组 Babel 插件, 扩展 Babel 功能
●@babel/preset-env: 一个智能预设,允许您使用最新的 JavaScript。
●@babel/preset-react:一个用来编译 React jsx 语法的预设
●@babel/preset-typescript:一个用来编译 TypeScript 语法的预设
- 在 Webpack 中使用
1.下载包
npm i babel-loader @babel/core @babel/preset-env -D
2.定义 Babel 配置文件
●babel.config.js
module.exports = {
presets: ["@babel/preset-env"],
};
3.配置
●webpack.config.js
module.exports={
module:{
rules:[
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules代码不编译
loader: "babel-loader",
},
]
}
}
package.json
{
"name": "mywepack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"serve": "webpack-dev-server"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"css-loader": "^6.7.3",
"css-minimizer-webpack-plugin": "^4.2.2",
"less-loader": "^6.2.0",
"node-sass": "^8.0.0",
"sass-loader": "^13.2.0",
"style-loader": "^3.3.1",
"terser-webpack-plugin": "^5.3.6",
"vue": "^2.7.14",
"vue-style-loader": "^4.1.3"
},
"devDependencies": {
"html-webpack-plugin": "^5.5.0",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1",
"webpack-dev-server": "^4.11.1",
"vue-loader": "^15.7.2",
"vue-template-compiler": "^2.6.10"
}
}
webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
// cpu核数
const os=require("os");
// 线程
const threads = os.cpus().length;
module.exports = {
mode: "development",
entry: path.resolve(__dirname, "/src/main.js"),
output: {
path: path.resolve(__dirname, "dist"),
filename: "build.js",
clean: true,
},
module: {
rules: [
// {
// test: /\.css$/i,
// use: ["style-loader", "css-loader"],
// },
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader"],
},
{
test: /\.s(a|c)ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.(jpg|jpeg|png|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 30 * 1024, // 小于10kb的图片会被base64处理
},
},
generator: {
filename: "./images/[hash:8][ext][query]",
},
},
{
test: /\.vue$/,
use: ["vue-loader"],
},
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
}
],
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "public/index.html"),
filename: "index.html",
inject: "body",
}),
new VueLoaderPlugin(),
],
optimization: {
minimizer: [
// css压缩也可以写到optimization.minimizer里面,效果一样的
new CssMinimizerPlugin(),
// 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了
new TerserPlugin({
parallel: threads, // 开启多进程
}),
]
},
// 开发服务器
devServer: {
compress:false,
host: "localhost", // 启动服务器域名
port: "3000", // 启动服务器端口号
open: true, // 是否自动打开浏览器
},
};