6.配置-灵析社区

懒人学前端

一、开发环境

开发环境调优

在之前的章节中我们介绍了 Webpack 的基础配置,一些 Loader 和 Plugin 的使用方法,到此我们应该对 Webpack 有了一定的认识,Webpack 作为打包工具的重要使命之一就是提升效率,下面我们介绍一些对日常开发有一定帮助的 Webpack 插件、配置。

  • source map
  • 插件介绍
  • 使用 webpack-dev-server
  • 模块热替换

source map

Webpack 打包编译后的代码基本不具备可读性,工程发布或启动后此时若代码跑出一个错误,想要回溯它的调用栈是非常困难的。而有了 source map 在加上浏览器的调试工具,要做到追踪错误和警告就容易的多了。source map 指的是将编译、打包、压缩等操作后的代码映射回原文件的过程。开发环境通过 source map 我们可以直接看到源代码调试,生产环境通过 source map 我们可以通过工具回溯到报错的代码位置。为我们进一步分析错误提供了便利。

在开发环境即 mode 选项设置为 development 模式下,Webpack 将自动生成映射文件,source map 除了将 Javascript 映射回原文件外,还同样适用于样式文件。

source map 配置

Javascript 的 source map 通过配置项 devtool 来启用,只要在 webpack.config.js 中添加 devtool 即可。

index.js

const divElement = document.createElement("div");
divElement.className = "demo";
divElement.innerHTML = 'mini-css-extract-plugin';
document.body.appendChild(divElement);

webpack.config.js

const path = require('path');
module.exports = {
    // ...
    devtool: 'source-map',
}

对于 CSS、SCSS、Less 来说,需要在 loader 中添加 source map 配置。

webpack.config.js

const path = require('path');
module.exports = {
    // ...
     module: {
        rules: [
            {
            test: /\.(css)$/,
            use: [
                'style-loader',
                {
                    loader: 'css-loader',
                    options: {
                        sourceMap: true
                    }
                }
              ]
            }
        ]
    },
}

打包后,在 dist 文件夹下除了 index.js 外还生成了一个 index.js.map 文件。在生成 mapping 文件的同时,还为 index.js 添加了一个引用注释,以便开发工具知道在哪里可以找到它。

dist/index.js

(function() {
  // 内容
})();
//# sourceMappingURL=index.js.map

当我们打开浏览器的开发者工具时,map 文件会同时被加载,这时浏览器会使用它来对打包后的 bundle 进行解析。分析出源码的内容。当我们打断点进行调试时,可以直接调试源码。

source map 分类

Webpack 支持的 source map 大概分为两种,inline(内连) 和 separate(独立)两种方式。inline 类型即生成的映射关系内容保存在 bundle 中不生成单独的文件,separate 类型即可生成单独的 map 文件可以独立使用。source map 支持类型很多,下面只介绍其中几种,详细信息可官网查看,source map官网

inline source map 类型

Webpack 提供了多种内联映射文件类型。通常 eval 是起点,因为它是速度和质量之间的良好折衷,同时在 Chrome 和 Firefox 浏览器中可以可靠地工作。下面我们介绍两个内连类型的例子。

注意:为了查看效果我们去掉 webpack.config.js 中的 mode 配置。

devtool: "eval"

eval生成代码,其中每个模块都包装在一个eval函数中。并且都包含 //# sourceURL,此选项会非常快的构建。

(()=>{var __webpack_modules__={
  138:()=>{
    eval('const divElement = document.createElement("div");\ndivElement.className = "demo";\ndivElement.innerHTML = \'mini-css-extract-plugin\';\ndocument.body.appendChild(divElement);\n\n//# sourceURL=webpack://6.1/./src/index.js?')
  }
},__webpack_exports__={};__webpack_modules__[138]()})();

devtool: "eval-source-map"

每个模块使用 eval() 执行,并且 source map 转换为 DataUrl 后添加到 eval() 中。初始化 source map 时比较慢,但是会在重新构建时提供比较快的速度,并且生成实际的文件。

(() =>
  {var __webpack_modules__={
    138: ()=>{
      eval('const divElement = document.createElement("div");\ndivElement.className = "demo";\ndivElement.innerHTML = \'mini-css-extract-plugin\';\ndocument.body.appendChild(divElement);//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMTM4LmpzIiwibWFwcGluZ3MiOiJBQUFBO0FBQ0E7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vNi4xLy4vc3JjL2luZGV4LmpzP2I2MzUiXSwic291cmNlc0NvbnRlbnQiOlsiY29uc3QgZGl2RWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJkaXZcIik7XG5kaXZFbGVtZW50LmNsYXNzTmFtZSA9IFwiZGVtb1wiO1xuZGl2RWxlbWVudC5pbm5lckhUTUwgPSAnbWluaS1jc3MtZXh0cmFjdC1wbHVnaW4nO1xuZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChkaXZFbGVtZW50KTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///138\n')
  }
},__webpack_exports__={};__webpack_modules__[138]()})();

separate source map 类型

Webpack 提供了多种独立映射文件类型。我们常用的为 source-map 类型,source-map 类型可以生成单独的 map 文件,有了 source map 也就意味着任何人都可以通过浏览器调试工具看到工程源码,这对于安全性来说有了极大隐患。那么如何能保证线上问题可以追踪又能防止源码泄漏,Webpack 提供了 hidden-source-map 和 nosources-source-map 两种策略来提升 source map 的安全性。

devtool: "hidden-source-map"

hidden-source-map 与 source-map 作用相同都会生成一个 map 文件,唯一区别是不会为 bundle 添加引用注释。我们在浏览器中直接打开工程,是看不到原文件的,生成的 map 文件只是作为我们追踪错误信息的依据。

(()=>{const e=document.createElement("div");e.className="demo",e.innerHTML="mini-css-extract-plugin",document.body.appendChild(e)})();
警告:你不应将 source map 文件部署到 web 服务器。而是只将其用于错误报告工具。

devtool: "nosources-source-map"

nosources-source-map 创建的 source map 不包含 sourcesContent(源代码内容)。虽然在 bundle 中增加了 //# sourceMappingURL,但是当我们在浏览器中打开源码文件时是看不到源码内容的。

index.js

(()=>{const e=document.createElement("div");e.className="demo",e.innerHTML="mini-css-extract-plugin",document.body.appendChild(e)})();
//# sourceMappingURL=index.js.map
这仍然会暴露反编译后的文件名和结构,但它不会暴露原始代码。

插件介绍

Webpack 拥有非常强大的生态系统,社区中相关的工具也是数不胜数,这里我们介绍两个项目中常用的插件,可以节省开发效率和减少我们操作步骤。

html-webpack-plugin

html-webpack-plugin 可以自动创建 html 文件,也支持使用 html 文件模版。html-webpack-plugin 会自动将所有必要的 css、javascript、manifest 和 favicon 文件注入到生成的 html 文件中。之前在 5.2 章节做过 html-webpack-plugin 的介绍,所以这里不在详细介绍。

安装 html-webpack-plugin

npm install html-webpack-plugin --save-dev

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...
  plugins: [
        ...
        new HtmlWebpackPlugin()
    ]
};

clean-webpack-plugin

clean-webpack-plugin 插件用于在每次构建工程时清除上次构建生成的文件,有了这个插件我们再也不用手动清除构建目录了。

安装 clean-webpack-plugin

npm install clean-webpack-plugin --save-dev

webpack.config.js

const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
...
  plugins: [
        ...
        new CleanWebpackPlugin()
    ]
};

使用 webpack-dev-server

在之前的案例中,我们一直都是更改代码后执行打包命令,然后手动去打包文件中打开 html 文件查看效果,这种方式在实际的项目发开中会增加很多额外的重复工作,并且打包后的内容需要发布到服务上才能被其他伙伴访问。为了提升开发效率,在构建代码并部署到生产环境之前,我们需要一个本地环境,用于运行我们开发的代码。这个环境相当于提供了一个简单的服务器,用于访问 webpack 构建好的静态文件,我们日常开发时可以使用它来调试前端代码。webpack-dev-server 可以很好的帮我们解决这个需求,webpack-dev-server 是 webpack 官方提供的一个工具,可以基于当前的 webpack 构建配置快速启动一个静态服务。当 mode 为 development 时,会具备 hot reload 的功能,即当源码文件变化时,会即时更新当前页面,以便我们实时看到效果。webpack-dev-server 仅应用于开发环境。下面简单介绍下 webpack-dev-server 的使用,详细配置可查看官网。

安装

npm install webpack-dev-server -D

package.json 中增加 scripts

  "scripts": {
    ...
    "serve": "webpack serve"
  },

配置成功后,命令行执行 npm run serve,项目启动成功并在控制台输出了网址,打开此网址即可运行我们现有代码。当我们修改 index.js 内容时页面会自动刷新。

模块热替换

当项目功能体量很大页面元素较多时,使用 webpack-dev-server 实现页面整体刷新会影响开发体验,这时我们会考虑使用模块热替换。

模块热替换(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一。HMR 功能会在应用程序运行过程中,替换、添加或删除模块,而无需重新加载整个页面。主要是通过以下几种方式,来显著加快开发速度:

  • 重新加载页面期间保留应用程序状态。
  • 只更新变更部分内容,节省开发时间。
  • 在源代码 CSS/JS 内容产生修改时,会立刻在浏览器中进行更新,这几乎相当于在浏览器 devtools 直接更改样式。

使用 HMR

HMR 是 Webpack 内置的插件,我们可以通过 webpack-dev-server 配置来开启 HMR。

webpack.config.js
module.exports = {
    ...
    devServer: {
        hot: true,
    }
}

上面的配置产生的结果是 Webpack 为每个模块绑定一个 module.hot 对象,这个对象可以调用 HMR 的 API。通过这些 API 我们可以对特定模块开启或关闭热替换。

index.js

const add = (a, b) => {
  return a + b;
};

const addRes = add(3, 5);
const divElement = document.createElement('div');
divElement.innerHTML = addRes;
document.body.appendChild(divElement);

if (module.hot) {
  module.hot.accept()
}

启动项目后可以在页面上看到结果 8,当修改 add 函数中的参数时,页面上 8 并没有清空,HMR 会使应用在当前浏览器环境下又执行来一遍 index.js (包括其依赖的模块)内容,但是页面本身并没有刷新。

调用 HMR API 可以如上面例子中手动调用,我们还可以借助现成的工具去调用,如 react-hot-loader、vue-loader 等。喜欢的小伙伴可以自行研究。

总结

本章我们介绍了 Webpack 开发环境下的常用的配置和插件以及如何使用 HMR。篇幅有限只写了些项目中用到的,Webpack 周边实用插件很多,感兴趣的小伙伴儿可以选择一些去使用一下,这对于了解 Webpack 也会有很大帮助。


阅读量:1719

点赞量:0

收藏量:0