Webpack配置案例
Webpack配置案例
PWA配置
::: tip 概念以及作用
PWA全称Progressive Web Application
(渐进式应用框架),它能让我们主动缓存文件,这样用户离线后依然能够使用我们缓存的文件打开网页,而不至于让页面挂掉,实现这种技术需要安装workbox-webpack-plugin
插件
:::
安装插件
1 | $ npm install workbox-webpack-plugin -D |
webpack.config.js文件配置
1 | // PWA只有在线上环境才有效,所以需要在webpack.prod.js文件中进行配置 |
以上配置完毕后,让我们使用npm run build
打包看一看生成了哪些文件,dist
目录的打包结果如下:
1 | |-- dist |
我们可以代码块高亮的部分,多出来了precache-manifest.xxxxx.js
文件和service-worker.js
,就是这两个文件能让我们实现PWA。
改写index.js
::: tip
需要判断浏览器是否支持PWA,支持的时候我们才进行注册,注册的.js
文件为我们打包后的service-worker.js
文件。
:::
1 | console.log('hello,world'); |
PWA实际效果
在npm run dev
后,我们利用webpack-dev-server
启动了一个小型的服务器,然后我们停掉这个服务器,刷新页面,PWA的实际结果如下图所示
WebpackDevServer请求转发
在这一小节中,我们要学到的技能有:
- 如何进行接口代理配置
- 如何使用接口路径重写
- 其他常见配置的介绍
假设我们现在有这样一个需求:我有一个URL地址(http://www.dell-lee.com/react/api/header.json
),我希望我请求的时候,请求的地址是/react/api/header.json
,能有一个什么东西能自动帮我把请求转发到http://www.dell-lee.com
域名下,那么这个问题该如何解决呢?
::: tip 解决办法
可以使用 Webpack 的webpack-dev-server
这个插件来解决,其中需要配置proxy
属性。
:::
如何进行接口代理配置
既然我们要做请求,那么安装axios
来发请求再合适不过了,使用如下命令安装axios
:
1 | $ npm install axios --save-dev |
因为我们的请求代理只能在开发环境下使用,线上的生产环境,需要走其他的代理配置,所以我们需要在webpack.dev.js
中进行代理配置
1 | const devConfig = { |
以上配置完毕后,我们在index.js
文件中引入axios
模块,再做请求转发。
1 | import axios from 'axios'; |
使用npm run dev
后, 我们可以在浏览器中看到,我们已经成功请求到了我们的数据。
如何使用接口路径重写
现在依然假设有这样一个场景:http://www.dell-lee.com/react/api/header.json
这个后端接口还没有开发完毕,但后端告诉我们可以先使用http://www.dell-lee.com/react/api/demo.json
这个测试接口,等接口开发完毕后,我们再改回来。
::: tip 解决办法
解决这个问题最佳办法是,代码中的地址不能变动,我们只在proxy
代理中处理即可,使用pathRewrite
属性进行配置。
:::
1 | const devConfig = { |
同样,我们打包后在浏览器中可以看到,我们的测试接口的数据已经成功拿到了。
其他常见配置的含义
转发到https: 一般情况下,不接受运行在https
上,如果要转发到https
上,可以使用如下配置
1 | module.exports = { |
跨域: 有时候,在请求的过程中,由于同源策略的影响,存在跨域问题,我们需要处理这种情况,可以如下进行配置。
1 | module.exports = { |
代理多个路径到同一个target: 代理多个路径到同一个target
,可以如下进行配置
1 | module.exports = { |
多页打包
现在流行的前端框架都推行单页引用(SPA),但有时候我们不得不兼容一些老的项目,他们是多页的,那么如何进行多页打包配置呢?
现在我们来思考一个问题:多页运用,即 多个入口文件+多个对应的html文件 ,那么我们就可以配置 多个入口+配置多个html-webpack-plugin
来进行。
::: tip 场景
假设现在我们有这样三个页面:index.html
, list.html
, detail.html
,我们需要配置三个入口文件,新建三个.js
文件。
:::
在webpack.common.js
中配置多个entry
并使用html-webpack-plugin
来生成对应的多个.html
页面。
HtmlWebpackPlugin参数说明:
template
:代表以哪个HTML页面为模板filename
:代表生成页面的文件名chunks
:代表需要引用打包后的哪些.js
文件1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26module.exports = {
// 其它配置
entry: {
index: './src/index.js',
list: './src/list.js',
detail: './src/detail.js',
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html',
filename: 'index.html',
chunks: ['index']
}),
new HtmlWebpackPlugin({
template: 'src/index.html',
filename: 'list.html',
chunks: ['list']
}),
new HtmlWebpackPlugin({
template: 'src/index.html',
filename: 'detail.html',
chunks: ['detail']
}),
new CleanWebpackPlugin()
]
}
在src
目录下新建三个.js
文件,名字分别是:index.js
,list.js
和detail.js
,它们的代码如下:
1 | // index.js代码 |
运行npm run build
进行打包:
1 | $ npm run build |
打包后的dist
目录:
1 | |-- dist |
随机选择list.html
在浏览器中运行,结果如下:
::: tip 思考
现在只有三个页面,即我们要配置三个入口+三个对应的html
,如果我们有十个入口,那么我们也要这样做重复的劳动吗?有没有什么东西能帮助我们自动实现呢?答案当然是有的!
:::
我们首先定义一个makeHtmlPlugins
方法,它接受一个 Webpack 配置项的参数configs
,返回一个plugins
数组
1 | const makeHtmlPlugins = function (configs) { |
通过调用makeHtmlPlugins
方法,它返回一个html
的plugins
数组,把它和原有的plugin
进行合并后再复制给configs
1 | configs.plugins = configs.plugins.concat(makeHtmlPlugins(configs)); |
以上配置完毕后,打包结果依然还是一样的,请自行测试,以下是webpack.commom.js
完整的代码:
1 | const path = require('path'); |
如何打包一个库文件(Library)
在上面所有的 Webpack 配置中,几乎都是针对业务代码的,如果我们要打包发布一个库,让别人使用的话,该怎么配置?在下面的几个小节中,我们将来讲一讲该怎么样打包一个库文件,并让这个库文件在多种场景能够使用。
创建一个全新的项目
::: tip 步骤
- 创建library项目
- 使用
npm init -y
进行配置package.json
- 新建
src
目录,创建math.js
文件、string.js
文件、index.js
文件 - 根目录下创建
webpack.config.js
文件 - 安装
webpack
、webpack-cli
:::
按上面的步骤走完后,你的目录大概看起来是这样子的:
1 | |-- src |
初始化package.json
1 | // 初始化后,改写package.json |
创建src目录,并添加文件
在src
目录下新建math.js
,它的代码是四则混合运算的方法,如下:
1 | export function add(a, b) { |
在src
目录下新建string.js
,它有一个join
方法,如下:
1 | export function join(a, b) { |
在src
目录下新建index.js
文件,它引用math.js
和string.js
并导出,如下:
1 | import * as math from './math'; |
添加webpack.config.js
::: tip 说明
因为我们是要打包一个库文件,所以mode
只配置为生产环境(production
)即可。
:::
在以上文件添加完毕后,我们来配置一下webpack.config.js
文件,它的代码非常简单,如下:
1 | const path = require('path'); |
安装Webpack
根据涉及到 Webpack 打包,所以我们需要使用npm instll
进行安装:
1 | $ npm install webpack webpack-cli -D |
进行第一次打包
使用npm run build
进行第一次打包,在dist
目录下会生成一个叫library.js
的文件,我们要测试这个文件的话,需要在dist
目录下新建index.html
1 | $ npm run build |
在index.html
中引入library.js
文件:
1 | <script src="./library.js"></script> |
至此,我们已经基本把项目目录搭建完毕,现在我们来考虑一下,可以在哪些情况下使用我们打包的文件:
- 使用
ES Module
语法引入,例如import library from 'library'
- 使用
CommonJS
语法引入,例如const library = require('library')
- 使用
AMD
、CMD
语法引入,例如require(['library'], function() {// todo})
- 使用
script
标签引入,例如<script src="library.js"></script>
::: tip 打包方案
针对以上几种使用场景,我们可以在output
中配置library
和libraryTarget
属性(注意:这里的library
和libraryTarget
和我们的库名字library.js
没有任何关系,前者是webpack
固有的配置项,后者只是我们随意取的一个名字)
:::1
2
3
4
5
6
7
8
9
10
11const path = require('path');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
library: 'library',
libraryTarget: 'umd'
}
}
配置属性说明:
- **
library
**:这个属性指,我们库的全局变量是什么,类似于jquery
中的$
符号 libraryTarget
: 这个属性指,我们库应该支持的模块引入方案,umd
代表支持ES Module
、CommomJS
、AMD
以及CMD
在配置完毕后,我们再使用npm run build
进行打包,并在浏览器中运行index.html
,在console
控制台输出library
这个全局变量,结果如下图所示:
以上我们所写的库非常简单,在实际的库开发过程中,往往需要使用到一些第三方库,如果我们不做其他配置的话,第三方库会直接打包进我们的库文件中。
如果用户在使用我们的库文件时,也引入了这个第三方库,就造成了重复引用的问题,那么如何解决这个问题呢?
::: tip 解决办法
可以在webpack.config.js
文件中配置externals
属性
:::
在string.js
文件的join
方法中,我们使用第三方库lodash
中的_join()
方法来进行字符串的拼接。
1 | import _ from 'lodash'; |
在修改完毕string.js
文件后,使用npm run build
进行打包,发现lodash
直接打包进了我们的库文件,造成库文件积极臃肿,有70.8kb。
1 | $ npm run build |
针对以上问题,我们可以在webpack.config.js
中配置externals
属性,更多externals
的用法请点击externals
1 | const path = require('path'); |
配置完externals
后,我们再进行打包,它的打包结果如下,我们可以看到我们的库文件又变回原来的大小了,证明我们的配置起作用了。
1 | $ npm run build |
如何发布并使用我们的库文件
在打包完毕后,我们如何发布我们的库文件呢,以下是发布的步骤:
::: tip 步骤
注册
npm
账号修改
package.json
文件的入口,修改为:"main": "./dist/library.js"
运行
npm adduser
添加账户名称运行
npm publish
命令进行发布运行
npm install xxx
来进行安装
:::
::: warning 注意为了维护
npm
仓库的干净,我们并未实际运行npm publish
命令,因为我们的库是无意义的,发布上去属于垃圾代码,所以为了维护npm
仓库的干净性,请自行尝试发布。自己包的名字不能和
npm
仓库中已有的包名字重复,所以需要在package.json
中给name
属性起一个特殊一点的名字才行,例如"name": "why-library-2019"
:::
TypeScript配置
随着TypeScript
的不断发展,相信未来使用TypeScript
来编写 JS 代码将变成主流形式,那么如何在 Webpack 中配置支持TypeScript
呢?可以安装ts-loader
和typescript
来解决这个问题。
新建一个项目webpack-typescript
::: tip
新创建一个项目,命名为webpack-typescript
,并按如下步骤处理:
- 使用
npm init -y
初始化package.json
文件,并在其中添加build
Webpack打包命令 - 新建
webpack.config.js
文件,并做一些简单配置,例如entry
、output
等 - 新建
src
目录,并在src
目录下新建index.ts
文件 - 新建
tsconfig.json
文件,并做一些配置 - 安装
webpack
和webpack-cli
- 安装
ts-loader
和typescript
:::
按以上步骤完成后,项目目录大概如下所示:1
2
3
4
5|-- src
| |-- index.ts
|-- tsconfig.json
|-- webpack.config.js
|-- package.json
在package.json
中添加好打包命令命令:
1 | "scripts": { |
接下来我们需要对webpack.config.js
做一下配置:
1 | const path = require('path'); |
在tsconfig.json
里面进行typescript
的相关配置,配置项的说明如下
module
: 表示我们使用ES6
模块target
: 表示我们转换成ES5
代码allowJs
: 允许我们在.ts
文件中通过import
语法引入其他.js
文件1
2
3
4
5
6
7{
"compilerOptions": {
"module": "ES6",
"target": "ES5",
"allowJs": true
}
}
在src/index.ts
文件中书写TypeScript
代码,像下面这样
1 | class Greeter { |
打包测试
- 运行
npm run build
进行打包 - 在生成
dist
目录下,新建index.html
,并引入打包后的main.js
文件 - 在浏览器中运行
index.html
使用其他模块的类型定义文件
::: tip 说明
如果我们要使用lodash
库,必须安装其对应的类型定义文件,格式为@types/xxx
:::
安装lodash
对应的typescript
类型文件:
1 | $ npm install lodash @types/lodash -D |
安装完毕后,我们在index.ts
中引用lodash
,并使用里面的方法:
1 | import * as _ from 'lodash' |
打包测试
使用npm run build
,在浏览器中运行index.html
,结果如下: