使用webpack打包前端代码(下)

532 阅读5分钟

如上一篇文章所述,配置好entry、output、loader之后,就已经可以完成基本的代码打包工作。除此之外webpack还提供了很多插件,可以简化一些繁琐的操作,比如自动清理打包生成目录等。

此外还提供sourceMap、devServer等多种开发利器。

Plugin

loader 是用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。插件接口功能极其强大,可以用来处理各种各样的任务。

通过以下实例,可以了解到插件到使用方式,更多插件API可以通过上述连接查阅。

CleanWebpackPlugin

clean-webpack-plugin插件可以在每次打包时自动清理(删除)之前残留的构建目录。

  • 安装
npm install --save -dev clean-webpack-plugin
  • 配置及使用
//webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin');

module.exports = {
  ...,
  plugin:[
    new CleanWebpackPlugin();
  ],
  ...
}

HtmlWebpackPlugin

wepack打包完成之后,自动生成一个html文件,并将打包好的js文件引入到html中。

  • 安装
npm install --save-dev html-webpack-plugin
  • 配置及使用
//webpack.config.js

const HtmlWebpackPlugin = require('html-webpack.plugin');

module.exports = {
  ...,
  plugin:{
    ...,
    new HtmlWebpackplugin({
      title:'app',
      filename:'app.html',
      template:'./src/html/index.html'
  }),
    ...
},
	... 
}
  • 模版./scr/html/index.html内容
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><%=htmlWebpackPlugin.options.title%></title> 
</head>

<body>
    <h1>html-webpack-plugin</h1>
</body>

</html>

MiniCssExtractPlugin

自动提取css相关配置,并导出到一个单独的.css文件中。

  • 安装
npm install --save-dev mini-css-extract-plugin
  • 配置及使用
const MiniCssExtactPlugin = require('mini-css-extract-plugin');

module.exports = {
  ...,
  plugin:{
  	...,
  	new MiniCssExtactPlugin({
  		filename:'./css/app.css'
}),
  	...
},
  ...
}

SourceMap

实际使用过程中,浏览器上运行的往往是webpack编译打包后的代码,如果代码报错,调试时往往比较麻烦、耗费很多时间定位问题原因。而sourceMap这给我们提供了一个映射关系(编译后的代码 => 编译前的代码),方便我们进行调试。

我们可以通过在webpack.config.js中的devtool选项来开始sourceMap。

//webpack.config.js
module.exports = {
  mode: 'production',
  devtool: 'source-map',
  ...
}
  • 编译后,sourceMap会给每一个编译后的文件生成一个对应的.map文件,并且在编译后的文件中添加一行注释来告诉浏览器,这个编译文件是有对应的映射表的。

  • 大部分现代浏览器如Chrome都是可以识别到.map文件的,在浏览器调试台中的source选项下可以看到由sourceMap提供的映射关系,这样大大提高了我们代码编写效率。

WebpackDevServer

每次的代码修改都需要重新编译打包,刷新浏览器,特别麻烦,我们可以通过安装 webpackDevServer 来改善这方面的体验。其功效很类似于vscode提供的插件:Live Server。每次我们更新代码时,devserver就会自动编译打包代码,并刷新浏览器(默认全局刷新)。

  • 安装
npm install --save-dev webpack-dev-server
  • 启用

    • 在命令行借助npx启用
    npx webpack-dev-server
    
    • 先在package.json的script中增加如下字段,然后在命令行中使用npm run build启用
    ...,
    "scripts": {
      "build": "webpack-dev-server" //可以自动在./node_moudle/.bin/目录下查找对应的webpack-dev-server文件
    }
    
  • 配置

//webpack.config.js

module.exports = {
  ...,
  devServer: {
  	// 生成的虚拟目录路径
  	contentBase: "./dist",
  	// 自动开启浏览器
  	open: true,
  	// devServer端口(默认8080)
  	port: 8888
	}
}

以下是devServer常用的配置选项:代理和局部热更新。更多配置相关API参见官网。

Proxy

主要用于解决跨域请求问题,原理为后端代理。

跨域:一种存在于浏览器上的安全策略;后端服务器上不存在跨域问题。

日常开发过程中,比如devserver配置的监听端口是8888,而后端某个特定服务API接口运行在8081端口上,那么当我们在某些业务逻辑上需要请求该API时就出现了跨域问题。这时候就需要通过devServer.proxy配置来进行处理。

  • 配置
//webpack.config.js

module.exports = {
  ...,
  devServer: {
  	// 生成的虚拟目录路径
  	contentBase: "./dist",
  	// 自动开启浏览器
  	open: true,
  	// devServer端口
  	port: 8888,
  	proxy: {
      '/api': {
      	target: 'http://localhost:8081' //8081指向API运行的服务器端口
    	}
    }
	}
}

要注意的是,前端代码依旧运行在devServer的环境下,也就是http://localhost:8888,当他调用/api的时候发往后端的请求是http://localhost:8888/api,devServer接收到请求之后再转发给8081端口,devServer实际发送的请求是http://localhost:8081/api

Hot Module Replacement

本身devServer是支持自动刷新页面的,使用的是live loader,但是这个是每当代码发生变化时自动刷新整个页面,而在实际工作中刷新整个页面往往会带来一些不方便的因素:比如,当页面中表单或者input框之类的,刷新就会丢掉填好的数据。为了解决这个问题,devServer为我们提供了不刷新整个月面而是局部刷新的方式。

模块热替换(HMR - hot module replacement)功能会在应用程序运行过程中,替换、添加或删除模块,而无需重新加载整个页面。主要是通过以下几种方式,来显著加快开发速度:

  1. 保留在完全重新加载页面期间丢失的应用程序状态。
  2. 只更新变更内容,以节省宝贵的开发时间。
  3. 在源代码中 CSS/JS 产生修改时,会立刻在浏览器中进行更新,这几乎相当于在浏览器 devtools 直接更改样式。

摘自官方文档

  • 配置
//webpack.config.js

module.exports = {
  ...,
  devServer: {
  	contentBase: "./dist",
  	open: true,
  	port: 8888,
  	// 开启热更新
  	hot:true,
  	// 即使 HMR 不生效,也不去刷新整个页面(选择开启)
    hotOnly:true,
    }
	}
}
  • 使用

    • 当开启HMR之后,将会暴露出一个module.hot属性。此时,当代码发生变化的时候,devServer就会立刻进行编译并通知浏览器进行局部刷新。因此我们需要对事件进行监听,当我们需要对模块发生变化的时候,进行立刻的局部刷新。
    //fn1.js
    
    export default function() {
        console.log('fn1模块执行了 -1');
    }
    
    //index.js
    
    import fn1 from './fn1.js';
    box1.onclick = fn1;
    
    if (module.hot) {//如果开启 HMR
        module.hot.accept('./fn1.js', function() {
          // accept方法,当监听事件发生变化时,接受并触发一个回调函数来响应更新
          box1.onclick = fn1;
        })
    }
    

以上便是对webpack学习的一些初步认识和探索,文章中的内容主要来自于:

​ 1.开课吧课程内容:www.kaikeba.com/

​ 2.webpack官方文档:webpack.js.org/concepts/

​ 3.自己的理解