接上一篇文章 Webpack基础配置
souceMap
在我们使用vue或者react开发项目时,最后会把源代码转换成js文件,这样做在调试代码的时候会发现代码的可读性很差,不方便调试,但是webpack为我们提供了souceMap的配置项。
sourceMap是一个信息文件,里面储存着位置信息。如果出现错误,通过他可以反向定位到源代码的位置,方便我们调试。开发环境默认开启,如果需要关闭,可以在配置文件里更改。安全起见,线上不推荐开启,会暴露源代码。
| devtool | 含义 |
|---|---|
| eval | 使⽤eval包裹模块代码,生成的映射代码性能、效率最佳,当代码复杂时,提示信息可能不精确 |
| source-map | 会生成独立的source Map文件,里面包含映射关系。该模式下会输出质量最高最详细的Source Map,但是构建速度很慢 |
| inline-source-map | 不会生成独立的map文件,但会把映射关系相关的代码放在打包后的文件中 |
| inline-cheap-source-map | 将错误只定位到行,不定位到列 |
| inline-cheap-module-source-map | module会映射loader和第三方库 |
配置推荐
devtool: 'cheap-module-eval-source-map' //开发环境配置
//线上不推荐开启
devtool: 'cheap-module-source-map' //线上生成配置
webpackDevServer
webpackDevServer是一个基于express的小型服务,可以提升我们的开发效率。
Webpack在启动时可以开启监听模式,默认不开启。而通过DevServer启动的Webpack会开启监听模式,当页面发生变化时,会重新构建后通知DevServer。DevServer会让Webpack在构建出的javaScript代码里注入一个代理客户端用于控制网页,网页和DevServer之间通过WebSocket协议通信,以方便DevServer主动向客户端发送命令。DevServer 在收到来自 Webpack 的文件变化通知时通过注入的客户端控制网页刷新。Webpack在启动时会以配置里的entry为入口去递归解析出entry所依赖的文件,只有entry本身和依赖的文件才会被Webpack添加到监听列表里。
- 安装
npm install webpack-dev-server -D
- 配置
修改package.json
"script": {
"dev": "webpack-dev-server"
}
修改webpack.config.js
devserver: {
contentBase: './dist',
open: true, //启动时自动在默认浏览器打开
port: 8081
}
- 启动
npm run dev
启动时发现dist下面的目录是空的,原因是 DevServer 会把 Webpack 构建出的文件保存在内存中。
- 本地mock,解决跨域
webpack.config.js
contentBase: './dist', //配置DevServer服务器的文件根目录,默认是项目根目录
open: true,
proxy: {
'/api': {
target: 'http://localhost:9092'
}
},
//mock server: 钩子函数,加载webpack devServe中间件之前和之后的钩子
before(app, server) {
//本地mock数据
app.get('/api/info', (req, res) => {
res.json({
hello: 'express'
})
})
},
after() {},
port: 8080
}
server.js
const express = require('express')
const app = express()
app.get('/api/info', (req, res) => {
res.json({
hello: 'express'
})
})
Hot Module Replacement(HMR:热模块替换)
通过devServer.hot可以配置是否开启热模块替换,默认不开启
Devserve 默认行为是发现源代码被更新后会通过自动刷新整个页面来做到实时预览,而热模块替换可以做到在不重新加载整个页面的情况下,只是用更新后的模块替换以前的模块,再重新执行一次来实现实时预览,相比于默认的配置,响应更快、开发体验更好。
//判断是否启用了HMR,如果启用了,就执行if语句中的代码;
if (module.hot) {
module.hot.accept('./count.js', function() {
console.log('Accepting the updated printMe module!');
count();
})
}
module.hot.accept('文件名',function (){
//当监听的文件发生变化时,就执行回调
));
这就是HMR实现的原理,由于style-loader已经帮我们实现了底层代码,因此只要我们配置hot:true并借助style-loader,就能够实现CSS的自动更新,但是JS的loader并没有实现,因此需要我们手动去实现,而各个框架库在相应的loader中都有实现,所以基本都可以做到开箱即用。
hot:true,
hotOnly: true // 即便是hot配置(HMR)没有生效,也不让浏览器进行刷新,失效时不做其他处理
- hot 和 hotOnly 的区别是在某些模块不支持热更新的情况下,前者会自动刷新页面,后者不会刷新页面,而是在控制台输出热更新失败
babel和ES6+
babel插件分两种,一种是语法转换,一种是语法解析。
Babel 是一个 JavaScript 编译器,能将 ES6 代码转为 ES5 代码,让你使用最新的语言特性而不用担心兼容性问题,并且可以通过插件机制根据需求灵活的扩展。在执行编译的过程中,会从根目录下的.babelrc的json文件中读取配置,没有该文件会从loader的options中读取配置。
-
其中的presets 属性告诉 Babel 要转换的源码使用了哪些新的语法特性,env 包含当前所有 ECMAScript 标准里的最新特性
-
babel-loader只是webpack和babel的一个通信桥梁,本身不做语法转换,这部分工作需要用到@babel/preset-env,里面包含了es6、7、8转成es5的转换规则,同时我们还需要用到babel的核心语法@babel/core
-
在webpack中配置babel需要用到babel-loader、@babel/core、@babel/preset-env,@babel/polyfill或者@babel/plugin-transform-runtime
-
@babel/polyfill和@babel/plugin-transform-runtime被称之为垫片,转换ES6+的一些新特性
@babel/polyfill
@babel/polyfill是以全局变量的方式注入进来,会污染全局对象,而且它是将整个模块完全加载进来,没有做到按需引入,导致打包的体积很大,但是我们可以配置按需引入。
options: {
presets: [
[
"@babel/preset-env",
{
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1"
},
corejs: 2,//新版本需要指定核⼼库版本
useBuiltIns: "entry"//按需注⼊
}
]
]
}
useBuiltIns 选项是 babel 7 的新功能,这个选项告诉 babel 如何配置 @babel/polyfill 。 它有三个参数可以使⽤:
- entry: 需要在 webpack 的⼊⼝⽂件⾥ import "@babel/polyfill" ⼀次。 babel 会根据你的使⽤情况导⼊垫⽚,没有使⽤的功能不会被导⼊相应的垫⽚。
- usage: 不需要import ,全⾃动检测,但是要安装 @babel/polyfill 。
- false: 如果你 import "@babel/polyfill" ,它不会排除掉没有使⽤的垫⽚,程序体积会庞⼤。(不推荐)
@babel/plugin-transform-runtime
由于polyfill会污染全局变量,当我们在开发组件库、工具库的时候就不适合使用了,这时就可以使用@babel/plugin-transform-runtime