十一、webpack:从零到精通
第一章 Webpack 简介?
🎉 什么是 Webpack?
webpack 是一种前端资源构建工具,一个静态模块打包器(module bundler)。 在 webpack 看来, 前端的所有资源文件(js/json/css/img/less/…)都会作为模块处理。 它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)。
🎉webpack 五个核心概念?
Entry
入口(Entry):指示 webpack 以哪个文件为入口起点开始打包,分析构建内部依赖图。
Output
输出(Output):指示 webpack 打包后的资源 bundles 输出到哪里去,以及如何命名。
Loader
Loader:让 webpack 能够去处理那些非 JS 的文件,比如样式文件、图片文件(webpack 自身只理解 JS)
Plugins
插件(Plugins):可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,
一直到重新定义环境中的变量等。
Mode
模式(Mode):指示 webpack 使用相应模式的配置。
选项 | 描述 | 特点 |
---|---|---|
development | 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development。启用 NamedChunksPlugin 和 NamedModulesPlugin。 | 能让代码本地调试运行的环境 |
production | 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 TerserPlugin。 | 能让代码优化上线运行的环境 |
第二章 Webpack 初体验?
🎉 初始化配置?
初始化 package.json:
1 | $npm init |
下载安装 webpack:
(webpack4 以上的版本需要全局/本地都安装 webpack-cli)
全局安装:
1 | $cnpm i webpack webpack-cli -g |
本地安装:
1 | $cnpm i webpack webpack-cli -D |
CNPM 介绍:
说明:因为谷歌安装插件是从国外服务器下载,受网络影响大,可能出现异常,如果谷歌的服务器在中国就好了,所以我们乐于分享的淘宝团队干了这事来自官网:“这是一个完整 npmjs.org 镜像,你可以用此代替官方版本(只读),同步频率目前为 10 分钟一次以保证尽量与官方服务同步“。
官方网址:http://npm.taobao.org
安装:命令提示符执行 npm install cnpm -g –registry=https://registry.npm.taobao.org
注意:安装完后最好查看其版本 cnpm -v 或关闭命令提示符重新打开,安装完直接使用有可能会出现错误
🎉 编译打包应用?
创建初始文件夹
输入入口:src 文件夹,在文件夹内新建 index.js。
输出出口:build 文件夹,作为输出文件的存放地址。
打包指令
开发环境:
webpack 会以 ./src/index.js 为入口文件开始打包,打包后输出到 ./build/built.js 整体打包环境,是开发环境。
1 | $webpack ./src/index.js ^ |
生产环境:
webpack 会以 ./src/index.js 为入口文件开始打包,打包后输出到 ./build/built.js 整体打包环境,是生产环境。
1 | $webpack ./src/index.js ^ |
注意:
1.webpack 本身能处理 js/json 资源,不能处理 css/img 等其他资源。
2.生产环境和开发环境将 ES6 模块化编译成浏览器能识别的模块化,
但是不能处理 ES6 的基本语法转化为 ES5(需要借助 loader)。
3.生产环境比开发环境多一个压缩 js 代码。
第三章 Webpack 开发环境的基本配置?
🎉Webpack 安装?
为了保障能够正常运行 Webpack,在开始项目前,可以在项目的根目录安装
🎉Webpack 定义配置文件?
webpack.config.js 是 webpack 的配置文件。
作用: 指示 webpack 干哪些活(当你运行 webpack 指令时,会加载里面的配置)
因此请将 webpack.config.js 放在打包文件的根目录里。
注意:所有构建工具都是基于 nodejs 平台运行的,模块化默认采用 commonjs。
基本的配置文件如下:
1 | //resolve用来拼接绝对路径 |
第四章 Webpack 打包资源?
🎉 打包前准备?
js 和 css 资源需要提前引入。
1 | import "./index.less"; |
🎉Webpack 打包 css/less 样式资源?
css 打包的方法
安装
使用前需要安装 style-loader 和 css-loader。
1 | $cnpm i style-loader css-loader -D |
修改配置
1 | rules: [ |
less 打包的方法
安装
使用前需要安装 style-loader、css-loader、less@xxx 和 less-loader。
1 | $cnpm i style-loader css-loader -D |
修改配置
1 | {//不同文件必须配置不同的loader处理 |
🎉Webpack 打包 loader 与 plugins 的区别?
loader:1.下载 2.使用(配置 loader)
plugins:1.下载 2.引入 3.使用
🎉Webpack 打包 html 和图片资源?
html 打包的方法
安装
使用前需要安装 html-webpack-plugin。
1 | $cnpm i html-webpack-plugin -D |
引入
1 | const HtmlWebpackPlugin = require("html-webpack-plugin"); |
修改配置
1 | plugins: [ |
图片打包的方法
教程中的 4.0 版本的教学在最新 5.0 版本中会报错,需要在 output 中加上
解决报错
1 | publicPath: "./"; |
安装
使用前需要安装 html-loader、file-loader 和 url-loader。
1 | $cnpm i html-loader file-loader url-loader -D |
修改配置
1 | //resolve用来拼接绝对路径 |
🎉其他资源的打包的方法
安装
使用前需要安装 file-loader。
1 | $cnpm i file-loader -D |
修改配置
然后修改配置。
1 | //当处理css、js、html之外的资源时 |
🎉 开发服务器_devServer 配置?
配置中出现的问题:
webpack-dev-server 并没有兼容最新版的 webpack-cli
会报错 Error: Cannot find module ‘webpack-cli/bin/config-yargs’
因此需要卸载最新版的脚手架
采用符合 webpack-dev-server 依赖的版本
卸载之前的 webpack-cli
1 | $npm uninstall webpack-cli |
安装符合依赖的 webpack-cli(webpack-dev-server 最新版对应 3.3)
1 | $npm install webpack-cli webpack-cli@3.3 -D |
详细配置:
1 | //用来自动化编译和hexo s差不多 |
🎉 最终开发环境配置?
切记单一 loader 请用 loader 不要用 use,不然会报错!!!
1 | //resolve用来拼接绝对路径 |
第五章 Webpack 生产环境的基本配置?
🎉 提取 css 成为单个文件?
安装插件
1 | $cnpm i mini-css-extract-plugin -D |
引入插件
1 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); |
插入插件
修改 ccs 使用的 loader
1 | { |
引入配置
通过修改 filename 修改 css 导出的路径。
1 | new MiniCssExtractPlugin({ |
🎉css 兼容性处理?
安装依赖插件
1 | $cnpm i postcss-loader postcss-preset-env autoprefixer -D |
配置项 webpack.config.js
1 | /* |
1 | use: [MiniCssExtractPlugin.loader, "css-loader", "postcss-loader"]; |
postcss 配置
在 webpack.config.js 同级目录新建 postcss.config.js 配置项。
1 | module.exports = { |
修改 package.json
1 | "browserslist":{ |
🎉 压缩 css 文件?
安装插件
1 | $cnpm i optimize-css-assets-webpack-plugin -D |
插件引入
1 | const OptimizeCssAssetWebpackPlugin = require("optimize-css-assets-webpack-plugin"); |
🎉js 语法检查?
安装插件
1 | $cnpm i eslint eslint-loader -D |
使用 airbnb 风格语言
1 | $cnpm i eslint eslint-plugin-import eslint-config-airbnb-base -D |
配置 package.json
1 | "eslintConfig":{ |
配置自动修复
1 | { //只检查自己写的代码,第三方库不用检查 |
忽略某一行(如 console.log)
加入注释,忽略下一行检查
1 | //eslint-disable-next-line |
🎉js 的基本兼容性问题?
安装插件
1 | $cnpm i babel-loader @babel/preset-env @babel/core@^7.0.0-0 -D |
新增配置
1 | { |
🎉js 的全部兼容性问题处理?(非常暴力,但已弃用)
安装插件
1 | $cnpm i @babel/pollyfill -D //已经弃用 |
使用
1 | import '@babel/pollyfill' //已经弃用 |
🎉js 的按需求处理兼容性问题?
安装插件
1 | $cnpm i core-js -D |
使用
1 | { |
🎉js 和 html 的压缩处理?
js 压缩
将 mode 从 development 变为 production。
1 | //mode: 'development', |
🎉 最终生产环境配置?
1 | //resolve用来拼接绝对路径 |
第六章开发环境webpack 性能优化?
🎉 基本介绍?
主要分为开发环境性能优化和生产环境性能优化。
开发环境的优化目的:优化打包速度及优化代码调试
生产环境的优化目的:优化代码打包速度及优化代码的性能
🎉 打包速度优化-HMR?
webpack 在使用 webpack-dev-server 时,如果你修改了打包原始文件中任意一项,打包会重新调用所有模块资源。为了实现资源的模块化刷新功能,需要使用 HMR(Hot module repalcement)——热模块替换/模块热替换。
一个模块变化,只会打包这一个模块,而不是打包所有
帮我们极大提升构建速度
方法
只需要在 dev-server 处开启 hot:true 就可以了
1 | devServer: { |
存在问题
CSS 样式文件:可以使用 HMR 功能,style-loader 内部实现
JS 文件:默认不能使用 HMR 功能 –》需要修改 js 代码,添加支持 mhr 功能的代码
HTML 文件:默认不能使用 HMR 功能,同时导致 html 文件不能热更新。在创建项目时只会创建 1 个 html 文件,当改变 js 和 css 时,html 一定会改,所以不需要 HMR。
解决策略
html 问题的解决措施为修改 entry 为数组并加入 html 文件,重启服务
1 | //入口起点 |
js 需要手动设置热更代码,只针对非入口文件的 js 来做。
1 | if (module.hot) { |
🎉 代码调试优化-source-map?
简介
source-map 是一种提供源代码到构建后代码映射的技术。
如果构建后的代码出错了,通过映射关系可以追踪到源代码的错误。
基本使用方法
只需加入 devtool:’source-map’即可。
1 | mode:'development', |
常用指令
1 | devtool: "xxx-source-map"; |
具体使用方法
1 | //开发环境,速度快,调试更友好--》eval-source-map |
第七章生产环境webpack 性能优化?
🎉 打包速度优化-oneOf?
概念
以下 loader 只会匹配一个。
1 | rules: [ |
注意
当两个 loader 处理同一种文件类型时,把其中一个放在 oneof 外面。
🎉 打包速度优化-缓存?
babel 缓存
开启 babel 缓存,第二次构建时会读取第一次的缓存。
1 | cacheDirectory: true; |
基本的服务器代码
1 | /* |
文件资源缓存
方案一 hash
1 | //使用哈希值,在webpack构建时将filename附上哈希值 |
方案二 chunkhash
1 | //根据chunk生成哈希值,如果打包来源于同一个chunk,那么哈希值就一样 |
最终方案三 contenthash
1 | //根据文件内容生成哈希值,如果文件内容不一样,那么哈希值就不一样 |
🎉 打包速度优化-多进程打包?
安装
使用前需要安装 html-webpack-plugin。
1 | $cnpm i thread-loader -D |
使用
在 use 中引入
1 | use: [thread - loader, xxx - loader]; |
使用多进程打包的利弊
启动需要 600 毫秒,进程通信也具有时间成本。如果本身打包时间较短,无需使用多进程打包。
只有工作时间较长才需要。
1 | {loader:thread-loader, |
🎉 代码性能优化-tree-shaking?
概念
将代码中未经应用的代码去除。
前提:1.使用 ES6 模块化 2.开启 production 环境
作用:减少代码体积
配置
在 package.json 中配置
“sodeEffects“:false 所有代码都没有副作用(都可以进行 tree shaking)
问题:可能会把 css/其他文件文件干掉
解决:
“sodeEffects“:[“*.css”]
🎉 代码性能优化-代码分割 code split?
多入口出口文件的重命名
1 | //将entry修改为对象,并对入口进行命名 |
多文件处理
1 | //1.optimization配置可以将node_modules中的代码单独打包成一个chunk最终输出 |
🎉 代码性能优化-lazy loading?
概念
当需要加载某个 js 的时候再进行加载
1 | //import {mul} form './test' |
🎉 代码性能优化-PWA?
简介
渐进式网络开发应用程序(离线可访问技术)
workbox –》 workbox-webpack-plugin
安装
使用前需要安装 html-webpack-plugin。
1 | $cnpm i workbox-webpack-plugin -D |
引入
1 | const WorkboxWebpackPlugin = require("workbox-webpack-plugin"); |
修改配置
1 | new WorkboxWebpackPlugin.GenerateSW({ |
注册 sw
1 | if('serviceWorker' in navigator){ |
存在的问题
1 | //1.eslint 不认识window、 navigator等变量。 |
🎉 代码性能优化-externals?
概念
将需要用 cdn 资源引入的 js 屏蔽掉。
方法
1 | externals: { |
🎉 代码性能优化-DLL?
概念
dll:让某些库单独打包,后直接引入到 build 中。可以在 code split 分割出 node_modules 后再用 dll 更细的分割,优化代码运行的性能。
配置
1 | /* |
webpack.config.js 配置:(告诉 webpack 不需要再打包 jquery,并将之前打包好的 jquery 跟其他打包好的资源一同输出到 build 目录下)
1 | // 引入插件 |
第八章 webpack 配置详解?
🎉entry?
string 类型
–> ‘./src/index.js’,单入口
打包形成一个 chunk。 输出一个 bundle 文件。此时 chunk 的名称默认是 main。
array 类型
–> [‘./src/index.js’, ‘./src/add.js’],多入口
所有入口文件最终只会形成一个 chunk,输出出去只有一个 bundle 文件。
(一般只用在 HMR 功能中让 html 热更新生效)。
object 类型
多入口,有几个入口文件就形成几个 chunk,输出几个 bundle 文件,此时 chunk 的名称是 key 值。
–> 特殊用法:
1 | entry: { |
🎉output?
配置
1 | output: { |
🎉module?
配置
1 | module: { |
🎉module?
配置
1 | // 解析模块的规则 |
这样配置后,引入文件就可以这样简写:import '$css/index';
🎉devServer?
配置
1 | devServer: { |
其中,跨域问题:同源策略中不同的协议、端口号、域名就会产生跨域。
正常的浏览器和服务器之间有跨域,但是服务器之间没有跨域。代码通过代理服务器运行,所以浏览器和代理服务器之间没有跨域,浏览器把请求发送到代理服务器上,代理服务器替你转发到另外一个服务器上,服务器之间没有跨域,所以请求成功。代理服务器再把接收到的响应响应给浏览器。这样就解决开发环境下的跨域问题。
contenthash 缓存会导致一个问题:修改 a 文件导致 b 文件 contenthash 变化。
因为在 index.js 中引入 a.js,打包后 index.js 中记录了 a.js 的 hash 值,而 a.js 改变,其重新打包后的 hash 改变,导致 index.js 文件内容中记录的 a.js 的 hash 也改变,从而重新打包后 index.js 的 hash 值也会变,这样就会使缓存失效。(改变的是 a.js 文件但是 index.js 文件的 hash 值也改变了)
解决办法:runtimeChunk –> 将当前模块记录其他模块的 hash 单独打包为一个文件 runtime,这样 a.js 的 hash 改变只会影响 runtime 文件,不会影响到 index.js 文件
🎉module?
配置
1 | output: { |
第九章 webpack5 的新特性?
🎉 重点内容?
此版本重点关注以下内容:
- 通过持久缓存提高构建性能.
- 使用更好的算法和默认值来改善长期缓存.
- 通过更好的树摇和代码生成来改善捆绑包大小.
- 清除处于怪异状态的内部结构,同时在 v4 中实现功能而不引入任何重大更改.
- 通过引入重大更改来为将来的功能做准备,以使我们能够尽可能长时间地使用 v5.
🎉 下载?(截止 2020 年 11 月已经可以直接下了)
1 | $cnpm i webpack webpack-cli -D |
🎉 自动删除 Node.js Polyfills?
早期,webpack 的目标是允许在浏览器中运行大多数 node.js 模块,但是模块格局发生了变化,许多模块用途现在主要是为前端目的而编写的。webpack <= 4 附带了许多 node.js 核心模块的 polyfill,一旦模块使用任何核心模块(即 crypto 模块),这些模块就会自动应用。
尽管这使使用为 node.js 编写的模块变得容易,但它会将这些巨大的 polyfill 添加到包中。在许多情况下,这些 polyfill 是不必要的。
webpack 5 会自动停止填充这些核心模块,并专注于与前端兼容的模块。
迁移:
- 尽可能尝试使用与前端兼容的模块。
- 可以为 node.js 核心模块手动添加一个 polyfill。错误消息将提示如何实现该目标。
Chunk 和模块 ID
添加了用于长期缓存的新算法。在生产模式下默认情况下启用这些功能。
1 | chunkIds: "deterministic", moduleIds: "deterministic" |
🎉Chunk ID?
你可以不用使用import(/* webpackChunkName: "name" */ "module")
在开发环境来为 chunk 命名,生产环境还是有必要的
webpack 内部有 chunk 命名规则,不再是以 id(0, 1, 2)命名了
🎉Tree Shaking?
- webpack 现在能够处理对嵌套模块的 tree shaking
1 | // inner.js |
在生产环境中, inner 模块暴露的b
会被删除
- webpack 现在能够多个模块之前的关系
1 | import { something } from "./something"; |
当设置了"sideEffects": false
时,一旦发现test
方法没有使用,不但删除test
,还会删除"./something"
- webpack 现在能处理对 Commonjs 的 tree shaking
🎉Output?
webpack 4 默认只能输出 ES5 代码
webpack 5 开始新增一个属性 output.ecmaVersion, 可以生成 ES5 和 ES6 / ES2015 代码.
如:output.ecmaVersion: 2015
SplitChunk
1 | // webpack4 |
🎉Caching?
1 | // 配置缓存 |
缓存将存储到node_modules/.cache/webpack
🎉 监视输出文件?
之前 webpack 总是在第一次构建时输出全部文件,但是监视重新构建时会只更新修改的文件。
此次更新在第一次构建时会找到输出文件看是否有变化,从而决定要不要输出全部文件。
🎉 默认值?
entry: "./src/index.js
output.path: path.resolve(__dirname, "dist")
output.filename: "[name].js"
尚硅谷 2020 最新版 Webpack5 实战教程(从入门到精通)
https://www.bilibili.com/video/BV1e7411j7T5?p=1