导读
学习了四节之后,我们对webpack可以说是已经有了深刻的认识,相信你也可以根据自己学到的内容对自己的网站等进行一系列的打包。
如果你是从第一节就跟着我走到这里的,那你就算我的webpack老战友了。这节当然你也会学到很多比较有趣的知识,例如:
- Library的打包
- 配置请求转发(代理跨域)
- Eslint/Typescript配置
- 多页面打包
- webpack性能优化
- 常用规范打包配置项等
let's go!
Library的打包
普通打包
将设我们现在想自己写一个库文件供自己和别人使用,那么我们应该如何去打包自己的库文件呢?
因为github已经提交了前四节的内容,为了不影响新伙伴的学习,我都是养成了新建文件的习惯,这里我就在新建一个文件夹,重新使用webpack来构建自己的库。
新建library目录,然后生成默认配置,并做一些简单的修改。
mkdir library
npm init -y
//package.json
{
"name": "library",
"version": "1.0.0",
"description": "this is my library",
"main": "index.js",
"scripts": {
},
"keywords": [],
"author": "jsxin",
"license": "ISC"
}
// install
npm install webpack webpack-cli --save
如果这一步你就看着有点吃力,建议你看看我的webpack的基本使用,花几分钟就能看懂我干了什么事(震惊!一男子竟然使用webpack干出了这种事)。
老规矩,我们自己写的js文件还是放在src下面。
// math.js
export function add(a, b) {
return a + b
}
export function minus(a, b) {
return a - b
}
export function multiplication(a, b){
return a * b
}
export function division(a, b){
return a / b
}
// string.js
export function join(a, b){
return a + ' ' + b
}
// index.js
import * as math from './math'
import * as str from './string'
console.log(math.add(1,3))
新建webpack.config.js,然后书写打包规则。然后在package.json中加入自己的脚本
// webpack.config.js
const path = require('path')
module.exports = {
entry: {
main: './src/index.js'
},
output: {
filename: 'library.js',
path: path.resolve(__dirname, 'dist')
}
}
// package.json
"build": "npx webpack"
简单的配置之后我们就可以使用 npm run build 命令进行打包了,然后生成了dist目录,为了验证我们的打包内容,我们先手动在dist目录下面新建index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>打包实战</title>
</head>
<body>
<script src="./main.js"></script>
</body>
</html>
然后使用live-server运行,在控制台就给我们输出了一个4,非常nice.
打包库
但是我们之前说过我们要打包的是一个库文件,也有供别人使用,在vue、react中我们去引入一个库经常是这么写的。
import xx from 'xx'
那么他是怎么根据xx来找到我们的库文件地址的呢?
我们先将我们的两个逻辑文件,在index.js中导出。
// index.js
import * as math from './math'
import * as str from './string'
export default { math, str }
然后我们在打包配置中,运行我们的文件通过任何方式引入。
const path = require('path')
module.exports = {
mode: 'production',
entry: {
main: './src/index.js'
},
output: {
filename: 'library.js',
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'umd',
library: 'library'
}
}
libraryTarget中我们使用umd,就代表可以通过模块引入,包引入等
import library from 'library'
const library = require('library')
require(['library'],()=>{})
script src = ''
...
我们还可以使用this, 然后使用就是this.library,挂载window,window.liarbry,在nodejs中global等等
一般都会和library一起使用,他将会作为我们使用时候的名字。
不打包重复引用库
我们虽然已经可以使用library了,但是我们的任务还没有完,如果我这个时候想改造一下我的string.js,我想使用lodash库来重新我的join方法。
// install
npm install lodash --save
// string.js
import _ from 'lodash'
export function join(a, b){
_.join([a,b],' ')
}
这个时候我们打包的时候,已经达到了72kb,如果别人在使用我们的库的时候,也使用了lodash呢?
import lodash from 'lodash'
import library from 'library'
所以这个时候就会存在两份lodash,当存在lodash的时候我们就不应该再把这个文件打包打我们的库文件里面 。
externals: 'lodash',
这样的话,检测到了lodash的时候就不会再将lodash打包到我们的库里。
那别人在使用的时候就应该现在业务代码上方引入lodash即可。
打包Ts文件
读过第二节的应该都知道,打包ts,就会遇到ts/tsx等文件结尾的,那我们我们就回去校验之后,使用指定的loader进行打包,先来看看我们会用到什么?
npm install ts-loader typescript -D
ts-loader对我们的ts文件进行打包,typescript负责读我们的ts代码,两个肯定是想结合的。安装好了之后我们直接配置打包。
module:{
rules: [{
test: /\.(ts|tsx)/,
use: ['ts-loader'],
exclude: /node_modules/
}]
}
exclude中我检测如果是node_modules里面的ts文件,那么我就不对其进行打包,这样下来,已经差不多了。
ok,报了一个错误,缺少一个tsconfig.json文件,我们在根目录下进行创建。
{
"compilerOptions": {
"outDir": "./dist",
"module": "ES6",
"target": "ES5",
"allowJs": true
}
}
- outDir:webpack打包的时候,编译目录会放在dist目录下
- module:使用的是es module的方式
- target:打包成es5语法
- allowJs:允许ts中引入js文件
再次打包,nice.
WebpackDevServer实现请求转发
跨域对于前端来说,常有的事,如果你有灵魂之问-什么是跨域?
...
先安装一下axios吧,用来做我们的请求。
npm install axios -S
然后稍稍show两句、加瓦斯溃普特
import axios from 'axios'
axios.get('https://www.fastmock.site/mock/13a9249208c0dbcf0e5f7cd2000f89ff/lists/lists')
.then(res => {
console.log(res)
})
非常nice的就拿到数据了,但是正常来说这里是应该跨域的,只不过人家的后端帮你解决了访问的限制而已。
那我们自己如何解决跨域访问的问题呢?
回到第三节的基本配置,我们先将之前讲过的配置稍微的配置一下。
devServer: {
contentBase: './dist',
open: true,
port: 8080,
hot: true,
hotOnly: true,
proxy: {
'/api': 'https://www.fastmock.site/mock/'
}
},
这样就可以将我们的接口代理到指定的网站,也是vue里面常用的跨域解决方式,这样看来就是使用webpack解决的。
配置Eslint
Eslint是什么
ESLint 是一个开源的 JavaScript 代码检查工具,就是为了规范团队代码的一个工具。(解释的有些...)
Eslint安装与初始化
npm install eslint -D
npx eslint --init
然后将我选择的选项贴出来吧...
这样就会在我的根目录下生成一个.eslintrc.js文件
Eslint代码检测
如果你想要检测代码规范,则可以使用
npx eslint file/dir
就会提示出不规范的代码,当然这样检测就会显得太麻烦,所以我们也可以直接在vscode中直接安装eslint插件,他就会在你代码不规范的时候报红。然后鼠标移动上去就可以直接提示出原因,我们对其修改即可。
Eslint-loader
如过要对eslint打包,我们首先还是会下载loader,因为他会告诉我们如何去打包这个文件。
npm install eslint-loader --save-dev
然后检测代码,我们通常会对js文件做代码检测
// webpack.config.js
{
test: /\.js$/,
exclude: /node_modules/,
use: ['babel-loader','eslint-loader']
}
但是这个时候我们打包的时候,还是会像命令行一样提示我们报错,所以我们在devserver中可以新增一个配置,如果有问题,他就会在浏览器中给我们弹出一个黑色的层,来告诉我们问题所在,相信很多使用vue框架的开发者对这个弹层并不感到陌生。
overlay: true,
ok,这样我们就把webpack和eslint以及webpackdevserver结合到了一起。
Webpack性能优化
如何提升打包速度
在一些大型项目中,我们会加载很多的资源,这样我们就必须提高打包项目的速度。
- 跟上技术的迭代
我们可以升级webpack的版本,node、npm/yarn的版本,我们为什么要升级这些工具呢?webpack在更新的时候,内部肯定会做出相应的优化,而webpack又是基于node,所以node的运行效率也会提升。npm/yarn我们引入包的时候,新的代码依赖或许会判断的更快等。所以我们跟上技术的迭代是必要的。
- 尽可能少的模块不适用loader
讲个例子,刚才配置的eslint,我会忽略node_modules,就是说遇到node_modules文件夹下面的代码,我们不去检测他, 这样我们就会只考虑自己的代码,这样就会提升不少效率,毕竟第三方代码基本上都是被编译过的。
- 插件合理使用
最好是使用官方校验过的,因为第三方我们对他的性能稳定不敢保证,随意因为可能会影响我们的打包效率。
- resolve参数合理配置
在react中,我们通常以jsx结尾,但是如果只是单纯的使用react,其实js也可以的,那么我们如何不写后缀,让他自动识别呢?我们可以使用resolve配置项。
在webpack.config.js中新增
resolve: {
extensions: ['.js', '.jsx']
},
这样他如果没有找到js文件,就会自动去找jsx文件。但是我们一般只是配置一些逻辑文件。
另外我们经常引入一个文件夹,他就会自动帮我们引入index.js这种文件,那我们如何自己配置自己想要进入的文件名称呢?
resolve: {
extensions: ['.js', '.jsx'],
mainFiles: ['index', 'child']
},
但是这里只做演示,一般不会这么配置的。
另外还有一个别名设置,可以关注一下,相信大家也知道这个是怎么使用的。
alias: {
axin: path.resolve(__dirname,'')
}
- 使用DLLPLUGIN提高打包速度
将第三方模块只打包一次,可以生成一个vendor.js,如果使用第三方模块,那就再vendor.js里面去找。 因为第三方模块的文件是不会经常变的,所以我们在第一次的时候就生成一个文件,将它保存起来。这样以后打包就不会再去分析,可以节约很多资源。
-
控制包文件大小
-
thread-loader,parallel-webpack,happypack多进程打包。
-
合理使用sourceMap(越详细,打包速度越慢)
-
结合stats分析打包结果
-
开发环境内存编译(内存读取会比硬盘读取快的多)
-
开发环境中无用插件剔除
...
多页面打包
现在的主流框架,例如vue,react等都属于单页应用,但是很老的网站比如jquery、zepto等都会涉及到多个页面。
先新建两个页面文件。home.html,list.html
之前也提到过,生成文件,使用的是webpack的一个插件 html-webpack-plugin
所以我们只需求在plugins里面配置即可。
new htmlPlugin({
template: './home.html',
filename: 'home.html', //生成的文件名字
chunks: ['main'] // 需要引入哪些东西
}),
new htmlPlugin({
template: './list.html',
filename: 'list.html',
}),
这样即可完成多页面打包。