webpack学习笔记(三):环境配置

734

前言

这是我学习webpack的第三篇笔记,前文之路

  • webpack学习笔记(一):初次见面,请多指教
  • webpack学习笔记(二):基本属性管理 在这一篇博客中,我想介绍的是如何进行webpack工程的环境配置。说到环境配置,很自然的就能想到之前提到过的 config.webpack.js 这个文件。没错,这个文件就是用来进行webpack环境配置的。但是,在实际的工程应用场合,需要将开发环境和生产环境分开进行配置,来达到工程优化的目的。在这篇博客中,主要介绍三个内容:开发环境,生产环境,环境变量。在学完这些东西之后,基本上就可以搭建一个简单的webpack工程模板了。

开发环境VS生产环境

前面两个笔记只是让webpack可以正常运行起来,但这远远不能满足实际开发的需要。在工程实践中,必然是要做到开发环境和生产环境分离的。在实际的开发中,需要做到:

  1. 提供http服务而不是在本地打开html文件看效果;
  2. 最好还能做到实时预览,而不是每次更改文件内容就得重新打包;
  3. 在开发中方便调试,准确定位出源文件的错误。 区别于开发环境,在生产环境中,我们更多的会关注压缩bundle、更轻量的source map、资源优化等。因此,我们需要将开发环境和生产环境分开。

开发环境

webpack开发环境的搭建分为以下三步:

  1. mode设置为development 在 config.webpack.js 文件中设置 mode 属性即可:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
 module.exports = {
   mode: 'development',          // 新添加的
   entry: {
     index: './src/index.js',
     print: './src/print.js',
   },
  devtool: 'inline-source-map',
   plugins: [
     new HtmlWebpackPlugin({
       title: 'Development',
     }),
   ],
   output: {
     filename: '[name].bundle.js',
     path: path.resolve(__dirname, 'dist'),
     clean: true,
   },
 };
  1. 使用source map追踪源文件中的错误 当使用webpack打包源代码时,在程序的执行过程中遇到错误会直接定位到打包好的bundle文件中,很难追溯到源代码中的错误。这就给代码的调试带来了很大的不便。
    为了解决这种调试的困难,JavaScript提供了source map的功能,可以将编译后的代码映射回源代码。这样就方便追踪程序执行过程中遇到的错误(error)和警告(warning)了。
    要使用source map,只需要在config.webpack.js文件中声明devtool属性即可:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    mode: 'development',
    entry: {
        index: './src/index.js',
        print: './src/print.js',
    },
    devtool: 'inline-source-map',        // 新添加的
        plugins: [
           new HtmlWebpackPlugin({
           title: 'Development',
         }),
    ],
    output: {
         filename: '[name].bundle.js',
         path: path.resolve(__dirname, 'dist'),
         clean: true,
    },
};

在这里的代码中使用的是inline-source-map选项。除此之外,还有其他的source-map选项,如下表所示:

devtool选项配置结果
source-map在一个单独的文件中产生一个完整且功能完全的文件。这个文件具有最好的source map但他会减慢打包速度
cheap-module-source-map在一个单独的文件中生成一个不带列映射的map,不带列映射提高了打包速度,但是也使得浏览器开发者工具只能对应到具体的行,不能对应到具体的列(符号),会对调试造成不便
eval-source-map使用eval打包源文件模块,在同一个文件中生成干净的完整的source map,但是对打包后输出的JS文件的执行具有性能和安全的隐患。在开发阶段这是一个非常好的选项,在生产阶段则一定不要启用这个选项
cheap-module-eval-source-map这是在打包文件时最快的生成source map的方法,生成的source map会和打包后的JavaScript文件同行显示,没有列映射,和eval-source-map选项具有相似的缺点

其中,eval-source-map对于小到中型项目而言是一个很好的选项,但是应该只在开发阶段使用它cheap-module-eval-source-map方法构建速度更快,但是不利于调试,推荐在大型项目考虑时间成本时使用

  1. 选择一种开发工具 webpack提供了三种在开发中方便调试的工具:
  • webpack's Watch Mode: 如果文件被更新,代码将被重新编译,无需手动创建
  • webpack-dev-server: 提供了一个基本的web server
  • webpack-dev-middleware: 可以把webpack处理过的文件发送到一个server,需要手动创建一个server

Watch Mode

这个工具不需要额外安装插件,只需要指示webpack "watch"则可以启动Watch Mode。如果采用npm script命令来运行,则需要在package.json文件中添加命令。

  • package.json:
 {
   "name": "webpack-demo",
   "version": "1.0.0",
   "description": "",
   "private": true,
   "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1",
    "watch": "webpack --watch",             // 新添加的
     "build": "webpack"
   },
   "keywords": [],
   "author": "",
   "license": "ISC",
   "devDependencies": {
     "html-webpack-plugin": "^4.5.0",
     "webpack": "^5.4.0",
     "webpack-cli": "^4.2.0"
   },
   "dependencies": {
     "lodash": "^4.17.20"
   }
 }

配置完成后,只需要运行如下命令即可。

npm run watch

webpack-dev-server

  1. 安装webpack-dev-server插件

npm install --save-dev webpack-dev-server

  1. 配置wepack.config.js
 const path = require('path');
 const HtmlWebpackPlugin = require('html-webpack-plugin');

 module.exports = {
   mode: 'development',
   entry: {
     index: './src/index.js',
     print: './src/print.js',
   },
   devtool: 'inline-source-map',
  devServer: {                           // 新添加的
    contentBase: './dist',               // 新添加的
  },                                     // 新添加的
   plugins: [
     new HtmlWebpackPlugin({
       title: 'Development',
     }),
   ],
   output: {
     filename: '[name].bundle.js',
     path: path.resolve(__dirname, 'dist'),
     clean: true,
   },
 };
  1. 添加直接运行dev server的script
"scripts": {
     "test": "echo \"Error: no test specified\" && exit 1",
     "watch": "webpack --watch",
     "start": "webpack serve --open",   // 新添加的
     "build": "webpack"
   },

webpack-dev-middleware

  1. 安装webpack-dev-middleware和express(根据需求选择安装的位置,如果仅在开发中需要,则安装在devDependencies中;如果在生产中也需要,则安装在dependencies中)

npm install --save-dev webpack-dev-middleware
npm install --save express 或者 npm install --save-dev express

  1. 调整webpack.config.js文件
const path = require('path');
 const HtmlWebpackPlugin = require('html-webpack-plugin');

 module.exports = {
   mode: 'development',
   entry: {
     index: './src/index.js',
     print: './src/print.js',
   },
   devtool: 'inline-source-map',
   devServer: {
     contentBase: './dist',
   },
   plugins: [
     new HtmlWebpackPlugin({
       title: 'Development',
     }),
   ],
   output: {
     filename: '[name].bundle.js',
     path: path.resolve(__dirname, 'dist'),
     clean: true,
     publicPath: '/',                // 新添加的
   },
 };
  1. 在工程目录添加server.js
webpack-demo
| - package.json
| - webpack.config.js
| - server.js                    // 新添加的
| - /dist
| - /src
    | - index.js
    | - print.js
| - /node_modules
  1. 编写server.js文件内容
const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');

const app = express();
const config = require('./webpack.config.js');
const compiler = webpack(config);

// 告知 express 使用 webpack-dev-middleware,
// 以及将 webpack.config.js 配置文件作为基础配置。
app.use(
  webpackDevMiddleware(compiler, {
    publicPath: config.output.publicPath,
  })
);

// 将文件 serve 到 port 3000。
app.listen(3000, function () {
  console.log('Example app listening on port 3000!\n');
});
  1. 添加直接运行server的script 在package.json文件中scripts添加相应的命令:
 "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1",
     "watch": "webpack --watch",
     "start": "webpack serve --open",
    "server": "node server.js",             // 新添加的
     "build": "webpack"
   },

生产环境

在这一部分中,首先需要做的是将生产环境和开发环境进行一个分离,即将webpack.config.js分成两个文件:webpack.dev.js 和 webpack.prod.js。这两个文件分别配置开发环境和生产环境。分开之后的文件目录如下:

webpack-demo
| - package.json
| - webpack.dev.js
| - webpack.prod.js
| - /dist
| - /src
    | - index.js
| - /node_modules

然后就是编写这两个文件中的配置:

  • webpack.dev.js
 const path = require('path');
 const HtmlWebpackPlugin = require('html-webpack-plugin');

 module.exports = {
   mode: 'development',
   devtool: 'inline-source-map',
   devServer: {
     contentBase: './dist',
   },
   entry: {
     app: './src/index.js',
   },
   plugins: [
     new HtmlWebpackPlugin({
       title: 'Production',
     }),
   ],
   output: {
     filename: '[name].bundle.js',
     path: path.resolve(__dirname, 'dist'),
     clean: true,
   },
 };
  • webpack.prod.js
 const path = require('path');
 const HtmlWebpackPlugin = require('html-webpack-plugin');

 module.exports = {
   mode: 'production',
   entry: {
     app: './src/index.js',
   },
   plugins: [
     new HtmlWebpackPlugin({
       title: 'Production',
     }),
   ],
   output: {
     filename: '[name].bundle.js',
     path: path.resolve(__dirname, 'dist'),
     clean: true,
   },
 };

最后,将scripts指向新的命令:

 "scripts": {
     "start": "webpack serve --open --config webpack.dev.js",
     "build": "webpack --config webpack.prod.js"
 },

容易发现,这两个文件中有很多相同的地方。本着不重复的原则,考虑将两个文件中相同的部分放到同一个文件webpack.common.js中,webpack.dev.js和webpack.prod.js中只放各自不同的配置即可。此时的目录结构变成:

webpack-demo
| - package.json
| - webpack.common.js
| - webpack.dev.js
| - webpack.prod.js
| - /dist
| - /src
    |- index.js
| - /node_modules

更改完文件目录之后,还应该安装一个可以将两个文件的配置合并在一起的插件:

npm install --save-dev webpack-merge 三个文件的代码如下:

  • webpack.common.js
 const path = require('path');
 const HtmlWebpackPlugin = require('html-webpack-plugin');

 module.exports = {
   entry: {
     app: './src/index.js',
   },
   plugins: [
     new HtmlWebpackPlugin({
       title: 'Production',
     }),
   ],
   output: {
     filename: '[name].bundle.js',
     path: path.resolve(__dirname, 'dist'),
     clean: true,
   },
 };
  • webpack.dev.js
 const { merge } = require('webpack-merge');
 const common = require('./webpack.common.js');

 module.exports = merge(common, {
   mode: 'development',
   devtool: 'inline-source-map',
   devServer: {
     contentBase: './dist',
   },
 });
  • webpack.prod.js
 const { merge } = require('webpack-merge');
 const common = require('./webpack.common.js');

 module.exports = merge(common, {
   mode: 'production',
 });

环境变量

webpack 命令行环境配置的 --env 参数,可以允许传入任意数量的环境变量。关于环境变量的访问问题,可以在 webpack.config.js 中可以访问到这些环境变量;也可以通过node环境获取:

process.env.NAME