从零到一学会webpack 02-搭建开发环境和热更新

189 阅读5分钟

接上一篇 从零到一学会webpack 01 - webpack构建应用

上篇文章中,我们已经实现了一个基础的webpack配置,满足我们对jsx和css提取、依赖文件提取的基本需求,并且可以实时监测我们代码的变动自动执行build.

但是,我们不可能通过这种方式开发项目 -- 打开本地生成的index.html的方式,因此我们需要一个开发环境,让开发体验更友好

搭建开发环境

注意:我们已经将webpack.config.js 的mode设置为了development(开发环境)

首先,我们配置 devtool: 'inline-source-map' 开启source-map 这个对开发调试定位错误很有用,可以直接定位到错误代码

使用webpack-dev-server

webpack-dev-server 为你提供了一个简单的网络服务器,并具有实时重新加载(实时重新加载)功能

yarn add webpack-dev-server -D

修改配置文件,告知dev服务器,从什么位置查找文件:

const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');


module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist/"),
    filename: "[name].bundle.js"
  },
  mode: "development",
  devtool: 'inline-source-map',
  devServer: {
    contentBase: './dist',
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /(node_modules|bower_components)/,
        loader: "babel-loader",
        options: { presets: ["@babel/env"] }
      },
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader"]
      }
    ]
  },
  resolve: { extensions: ["*", ".js", ".jsx"] },
  plugins: [
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin(),
    new HtmlWebpackPlugin({
      title: '管理输出',
      template: './public/index.html'
    }),
  ],
  optimization: {
    splitChunks: {
      chunks: 'all',
    },
  },
};

以上配置通知webpack-dev-server,将dist目录下的文件服务到localhost:8080下;

webpack-dev-server从会output.path中定义的目录为服务提供束文件,即,将文件可以通过http://[devServer.host]:[devServer.port]/[output.publicPath]/[output.filename]进行访问。

我们添加一个可以直接运行dev server的脚本在package.json:

...
  "scripts": {
    "watch": "webpack --watch",
    "dev": "webpack serve --open",
    "build": "webpack"
  }
...

尝试执行 yarn dev你就能看到效果

更新src文件夹的代码,页面会自动刷新~

使用webpack-dev-middleware

webpack-dev-middleware是一个封装器(wrapper),它可以把webpack处理过的文件发送到一个服务器。webpack-dev-server在内部使用了它,而它也可以作为一个单独的包来使用

首先,安装express和 webpack-dev-middleware

yarn add webpack-dev-middleware -D

yarn add express

webpack-dev-middleware作为一个中间件使用 首先我们需要修改webpack.config.js的output配置

  output: {
    path: path.resolve(__dirname, "dist/"),
    filename: "[name].bundle.js",
    publicPath: '/',
  }

我们将会在服务器脚本使用publicPath,以确保文件资源能够正确地投放在http://localhost:3000下,稍后我们会指定端口号(端口号)接下来是设置自定义

express服务器: 在根目录新增一个server.js的文件 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');
});

现在,添加一个npm script,以使我们更方便地运行server:

  "scripts": {
    "watch": "webpack --watch",
    "dev": "webpack serve --open",
    "server": "node server.js",
    "build": "webpack"
  },

执行yarn server试试看

现在,打开浏览器,访问http://localhost:3000应该看到webpack应用程序已经运行! 更新src中的代码发现,终端的webpack有重新运行,但是页面并没有实时刷新(需要手动刷新页面),这是因为,使用webpack-dev-middleware的话还需要配置HMR(==只适用开发环境==)

HMR

热替换(hot module replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允许在运行时更新所有类型的模块,而无需完全刷新

启用 HMR

webpack-dev-server内置支持HMR上文中我们有演示,如果您在技术选型中使用了webpack-dev-middleware而没有使用webpack-dev-server,请使用webpack-hot-middleware依赖包,以在您的自定义服务器或应用程序上启用HMR

==webpack-hot-middleware 是和webpack-dev-middleware配套使用的==

yarn add webpack-hot-middleware -D

这里需要做几处改动:

  1. webpack.config.js需要增加entry文件、plugins增加webpack.HotModuleReplacementPlugin
...
  entry: ["./src/index.js", 'webpack-hot-middleware/client'],
...
  plugins: [
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin(),
    new HtmlWebpackPlugin({
      title: '管理输出',
      template: './public/index.html'
    }),
    new webpack.HotModuleReplacementPlugin()
  ],
...
  1. server.js中
const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-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,
  })
);

app.use(webpackHotMiddleware(compiler, {
  path: '/__webpack_hmr',
}));

// 将文件 serve 到 port 3000。
app.listen(8080, function () {
  console.log('Example app listening on port 3000!\n');
});

3.还有一个很重要的点:入口文件需要告知 webpack 允许此模块的热更新 在src/index.js 末尾增加

//灰常重要,知会 webpack 允许此模块的热更新
if (module.hot) {
    module.hot.accept();
}

再重新执行 yarn server,大功告成!

通过 Node.js API

==首先恢复上述通过webpack-hot-middleware 是和webpack-dev-middleware配套使用的而分三步配置的代码==

在 Node.js API 中使用 webpack dev server 时,不要将 dev server 选项放在 webpack 配置对象中。而是在创建时, 将其作为第二个参数传递。例如:new WebpackDevServer(compiler, options),想要启用 HMR,还需要修改 webpack 配置对象,使其包含 HMR 入口起点。webpack-dev-server 依赖包中具有一个叫做 addDevServerEntrypoints 的方法,你可以通过使用这个方法来实现

在根目录新增dev-server.js

const webpackDevServer = require('webpack-dev-server');
const webpack = require('webpack');

const config = require('./webpack.config.js');
const options = {
  contentBase: './dist',
  hot: true,
  host: 'localhost',
};

webpackDevServer.addDevServerEntrypoints(config, options);
const compiler = webpack(config);
const server = new webpackDevServer(compiler, options);

server.listen(5000, 'localhost', () => {
  console.log('dev server listening on port 5000');
});

package.json中

  "scripts": {
    "watch": "webpack --watch",
    "dev": "webpack serve --open",
    "server": "node dev-server.js", // 注意这里执行yarn server后执行的代码是dev-server.js
    "build": "webpack"
  },

执行 yarn server 同样达到了我们热更新的目的

下一篇,我们储备一下有关缓存的知识 从零到一学会webpack 03-缓存