前言
这是我花了几个星期学习 webpack4 的学习笔记。内容不够细,因为一些相对比较简单的,就随意带过了。希望文章能给大家带来帮助。如有错误,希望及时指出。例子都在learn-webpack仓库上。如果你从中有所收获的话,希望你能给我的github
点个star
。
library
当你要开发第三方库供别人使用时,就需要用到library
和libraryTarget
这两个配置了。
library
1 | output: { |
library
: 当配置了这个library
参数后,会把library
这个key
对应的value
即上面代码library
挂载到全局作用域中。html
用script
标签引入,可以通过访问全局变量library
访问到我们自己开发的库。
libraryTarget
:这个默认值为var
。意思就是让 library 定义的变量挂载到全局作用域下。当然还有浏览器环境的window
,node
环境的global
,umd
等。当设置了window
、global
,library
就会挂载到这两个对象上。当配置了umd
后,你就可以通过import
,require
等方式引入了。
externals
exterals
是开发公共库很重要的一个配置。当你的公共库引入了第三方库的时候,公共库会把该第三方库也打包进你的模块里。当使用者也引入了这个第三方库后,这个时候打包就会又打了一份第三方库进来。
所在在公共模块库中配置如下代码
1 | externals: { |
前面的lodash
是我的库里引入的包名 比如import _ from 'lodash'
,后面的lodash
是别人业务代码需要注入到他自己模块的lodash
比如 import lodash from 'lodash'
,注意不能import _ from 'lodash'
,因为配置项写了lodash
就不能import _
。
本人做了个试验,当自己开发的包不引入lodash
,业务代码中也不引入lodash
,那么打包业务代码的时候,webpack
会把lodash
打进你业务代码包里。
当然externals
,配置还有多种写法,如下
1 | externals: { |
具体请参考官网externals
发布自己开发的 npm 包
学了上面的配置后,就需要学习下如何将自己的包发布到npm
仓库上了。
package.json
的入口要改成dist
目录下的 js 文件如:"main": "./dist/library.js"
注册 npm 账号。npm 会发送一份邮件到你的邮箱上,点击下里面的链接进行激活。
命令行输入
npm login
进行登录,或者npm adduser
添加账号npm publish
当出现如下提示代表发布成功
1 | // 当出现类似如下代码时,表示你已经发布成功 |
遇到的问题:
当你遇到npm ERR! you must verify your email before publishing a new package
说明你还没有激活你的邮箱,去邮箱里点击下链接激活下就 ok 了
当你已经登录了提醒npm ERR! 404 unauthorized Login first
,这个时候你就要注意下你的npm
源了,看看是否设置了淘宝源等。记得设置回来npm config set registry https://registry.npmjs.org/
PWA
http-server
workbox-webpack-plugin
相信很多朋友都有耳闻过PWA
这门技术,PWA
是Progressive Web App
的英文缩写, 翻译过来就是渐进式增强 WEB 应用, 是 Google 在 2016 年提出的概念,2017 年落地的 web 技术。目的就是在移动端利用提供的标准化框架,在网页应用中实现和原生应用相近的用户体验的渐进式网页应用。
优点:
- 可靠 即使在不稳定的网络环境下,也能瞬间加载并展现
- 快 快速响应,并且 动画平滑流畅
应用场景:
当你访问正常运行的服务器页面的时候,页面正常加载。可当你服务器挂了的时候,页面就无法正常加载了。
这个时候就需要使用到 pwa 技术了。
这里我编写最简单的代码重现下场景:
1 | // webpack.config.js |
执行下npm run build
1 | . |
为了模拟服务器环境,我们安装下http-server
npm i http-server -D
配置下package.json
,"start": "http-server ./dist"
执行npm run start
来启动 dist 文件夹下的页面
这个时候控制台会正常打印出'this is outer console'
当我们断开http-server
服务后,在访问该页面时,页面就报 404 了
这个时候就需要使用到 pwa 技术了
使用步骤:
安装: npm i workbox-webpack-plugin -D
webpack 配置文件配置:
1 | // webpack.config.js |
这里我们写一个最简单的业务代码,在注册完 pwa 之后打印下内容:
1 | // index.js |
执行下打包命令:npm run build
1 | . |
打包之后会生成个service-worker.js
与precache-manifest.e21ef01e9492a8310f54438fcd8b1aad.js
接下来再重启下http-server
服务:npm run start
页面将会打印出
1 | this is outer console |
然后我们再断开http-server
服务
刷新下页面,竟然打印出了相同的代码。说明 pwa 离线缓存成功。
typescript
使用 webpack 打包 ts 文件,就需要安装ts-loader
安装:npm i ts-loader typescript -D
webpack.config.js
文件中添加解析typescript
代码的loader
1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); |
配置了webpack.config.js
还不行,还得在根目录文件下新增个.tsconfig.json
文件
1 | { |
新建index.ts
1 | class Greeter { |
执行打包命令,访问打包后的页面,页面正常执行。
当需要使用lodash
等库时,
需安装:npm i @types/lodash -D
修改页面代码 引入 lodash
1 | import * as _ from 'lodash'; |
提醒:ts 使用的包,可通过https://microsoft.github.io/TypeSearch
这个网址去查对应的包使用指南
使用WebpackDevServer
实现请求转发
当我们工作本地开发某一个需求的时候,需要将这块需求的请求地址转发到某个后端同事的本地服务器或某个服务器上,就需要用到代理。然后其他页面的请求都走测试环境的请求。那么我们该怎样拦截某个请求,并将其转发到我们想要转发的接口上呢?
这个时候就需要用到webpack-dev-server
主要看devServer
配置:
1 | // webpack.config.js |
1 | // package.json |
1 | // index.js |
在写一个本地启动的服务端代码
1 | const express = require('express'); |
执行npm run server
命令,浏览器会自动打开页面。点击 div 后,会发起请求。
浏览器提示http://localhost:8080/api/list 404 (Not Found)
,表示该接口不存在。
因为我们webpack
启动静态资源服务器默认端口为 8080,所以他求会直接请求到 8080 的/api/list 接口。所以会提示找不到该接口。
为了解决这个问题,我们就需要将该请求从 8080 端口代理到 8888 端口(也就是我们自己本地启动的服务)
配置webpack.config.js
这里我只展示devServer
代码
1 | // webpack.config.js |
配置devServer
的proxy
字段的参数,将请求/api
开头的请求都转发到http://localhost:8888
,
通过这个方法可以解决一开始提到的本地开发的时候,只想把部分接口转发到某台部署新需求的服务器上。比如当你这个项目请求很多,不同接口部署在不同的端口或者不同的服务器上。那么就可以通过配置第一个路径,来区分不同的模块。并转发到不同的服务上。如:
1 | // webpack.config.js |
当你要代理到某个 https 的接口上,就需要设置secure: false
1 | // webpack.config.js |
1 | target: '', // 代理的目标地址 |
其他关于devServer
的配置详见devServer
WebpackDevServer 解决单页面路由 404 问题
相信大家都是开发过 vue 或者 react 单页面带路由的应用。这里就忽略业务代码,介绍下devServer
的historyApiFallback
参数
1 | devServer: { |
eslint
安装eslint
: npm i eslint -D
目录下新建.eslintrc.json
文件。
environment
: 指定脚本的运行环境
globals
: 脚本在执行期间访问的额外全局变量。
rules
: 启动的规则及其各自的错误级别。
解析器选项
: 解析器选项
编辑你的eslint
的规则
1 | { |
vscode
安装eslint
插件。
配置下webpack.config.js
配置。
1 | ... |
eslint-loader
是用于检查js
代码是否符合eslint
规则。
这里devServer
中的overlay
的作用是,当你 eslint 报错的时候,页面会有个报错蒙层。这样就不局限于编辑器(vscode)的报错提醒了。
如果 js 代码使用了多个 loader,那么 eslint-loader 一定要写在最右边。如果不写在最后一个的话,需在里面添加enforce: "pre"
,这样不管写在哪个位置都会优先使用eslint-loader
校验下代码规范。
1 | { |
提升webpack
打包速度的方法
1. 跟上技术的迭代
- 升级
webpack
版本node
版本npm
等版本
2. 尽可能少的模块上应用loader
include
exclude
3. 尽可能少的使用plugin
4. resolve
1 | resolve: { |
extensions
: 可以让你 import 模块的时候不写格式,当你不写格式的时候,webpack 会默认通过 extensions 中的格式去相应的文件夹中找
alias
:当你import
的路径很长的时候,最好使用别名,能简化你的路径。
比如:import index.js from '../src/a/b/c/index.js'
设置别名:
1 | resolve: { |
这样你的import
导入代码就可以改成import index.js from '@c/index.js'
5. dllPlugin
我们先记录下不使用dll
打包时间787ms
:
1 | Time: 787ms |
接下来我们就尝试使用dll
技术
我们先配置一个用于打包dll
文件的webpack
配置文件,生成打包后的js
文件与描述动态链接库的manifest.json
1 | // webpack.dll.config.js |
重点:这里引入的 DllPlugin 插件,该插件将生成一个 manifest.json 文件,该文件供 webpack.config.js 中加入的 DllReferencePlugin 使用,使我们所编写的源文件能正确地访问到我们所需要的静态资源(运行时依赖包)。
配置下package.json
文件的scripts
: "build:dll": "webpack --config webpack.dll.config.js"
执行下 npm run build:dll
1 | Time: 548ms |
除了打包出dll
文件之外,还得再主webpack
配置文件中引入。这里就需要使用到DllReferencePlugin
。具体配置如下:
1 | // webpack.config.js |
这里的manifest
:需要配置的是你dllPlugin
打包出来的manifest.json
文件。让主webpack
配置文件通过这个
描述动态链接库manifest.json
文件,让js
导入该模块的时候,直接引用dll
文件夹中打包好的模块。
看似都配置好了,接下来执行下命令 npm run build
使用dll
打包后时间:
1 | Time: 471ms |
直接从最开始的787ms
降低到471ms
,当你抽离的第三方模块越多,这个效果就越明显。
浏览器跑下html
页面,会报错
Uncaught ReferenceError: vendor_e406fbc5b0a0acb4f4e9 is not defined
这是因为index.html
还需要通过script
标签引入这个dll
打包出来的js
文件
我们如果每次自己手动引入的话会比较麻烦,如果dll
文件非常多的话,就难以想象了。
这个时候就需要借助add-asset-html-webpack-plugin
这个包了。
1 | const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin'); |
通过这包,webpack
会将dll
打包出来的js
文件通过script
标签引入到index.html
文件中
这个时候你在npm run build
,访问下页面就正常了
6. 控制包文件大小
tree-shaking 等
7. thread-loader parallel-webpack happypack 等多进程打包
8. 合理使用 sourceMap
9. 结合 stats 分析打包结果
借助线上或者本地打包分析工具
10. 开发环境内存编译
开发环境的时候不会生成 dist 文件夹,会直接从内存中读取,因为内存读取比硬盘读取快
11. 开发环境无用插件剔除
F