webpack 4 入门指南 系列五(开发篇)

本教程使用基于输出管理教程的代码示例。

  • 如果你一直遵循这些教程,那你应该会对webpack的基本知识有充分的了解。在我们继续之前,让我们先来看看如何建立一个开发环境,让我们的开发生活更轻松一些。

这篇教程中的所有工具都只适用于开发环境,请避免在生成环境使用。

使用源代码映射(source map)

  • webpack打包源代码时,想要在原来的位置追踪错误和警告将会变得很困难。例如,如果你把这些文件 (a.js, b.js, 和c.js)打包进bundle(bundle.js),并且其中一个源文件有错误,堆栈踪迹只会简单的指向bundle.js。当你想确切的知道错误是从哪个源文件产生的时候,这种提示几乎没什么用。

  • 为了使追踪错误和警告变得简单点,JavaScript提供了source maps,将编译后的代码映射回源代码。如果错误来源于b.jssource map会明确的告诉你。

  • source map有很多可用的选项,请确保你的配置是能够满足你的需要的。

  • 对本教程来说, 将会使用 inline-source-map选项,这对于简单说明目的很好(尽管不适用于生产环境):

webpack.config.js

  const path = require('path');
  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const CleanWebpackPlugin = require('clean-webpack-plugin');

  module.exports = {
    entry: {
      app: './src/index.js',
      print: './src/print.js'
    },
+   devtool: 'inline-source-map',
    plugins: [
      new CleanWebpackPlugin(['dist']),
      new HtmlWebpackPlugin({
        title: 'Development'
      })
    ],
    output: {
      filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist')
    }
  };
  • 为了让我们能够调试代码,我们在print.js创造一个错误:
  export default function printMe() {
-   console.log('I get called from print.js!');
+   cosnole.log('I get called from print.js!');
  }
  • 执行构建命令,可能会编译成这样:
Hash: 7bf68ca15f1f2690e2d1
Version: webpack 3.1.0
Time: 1224ms
          Asset       Size  Chunks                    Chunk Names
  app.bundle.js    1.44 MB    0, 1  [emitted]  [big]  app
print.bundle.js    6.43 kB       1  [emitted]         print
     index.html  248 bytes          [emitted]
   [0] ./src/print.js 84 bytes {0} {1} [built]
   [1] ./src/index.js 403 bytes {0} [built]
   [3] (webpack)/buildin/global.js 509 bytes {0} [built]
   [4] (webpack)/buildin/module.js 517 bytes {0} [built]
    + 1 hidden module
Child html-webpack-plugin for "index.html":
       [2] (webpack)/buildin/global.js 509 bytes {0} [built]
       [3] (webpack)/buildin/module.js 517 bytes {0} [built]
        + 2 hidden modules
  • 现在在浏览器打开产生的index.html文件。在点击按钮式查看控制台就会发现错误。可能是这样的错误:
 Uncaught ReferenceError: cosnole is not defined
    at HTMLButtonElement.printMe (print.js:2)
  • 我们看到包含一个引用指向文件(print.js)已经错误发生的位置第2行。很好,现在我们知道要想解决这个问题该去哪了。

选择开发工具

一些文本编辑器有“safe write”功能,可能影响接下来的工具。查看调整你的编辑器来解决这些问题。

  • 每当你想编译代码时,手动运行npm run build是很麻烦的。

  • webpack中有一组不同的选项可以在代码发生改变时帮你自动编译。

    • webpack 的Watch模式
    • webpack-dev-server
    • webpack-dev-middleware
  • 大多数情况下,你可能会使用webpack-dev-server,但是我们来探索下上面所有的选项吧。

使用 watch 模式

  • 你可以命令webpack“监视”依赖关系图中所有文件的改变。只要其中一个文件发生改变,该文件的代码就会重新编译,你就不用每次都手动全部构建了。

  • 我们添加一个npm脚本来开启webpackWatch模式:

  {
    "name": "development",
    "version": "1.0.0",
    "description": "",
    "main": "webpack.config.js",
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
+     "watch": "webpack --watch",
      "build": "webpack"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
      "clean-webpack-plugin": "^0.1.16",
      "css-loader": "^0.28.4",
      "csv-loader": "^2.1.1",
      "file-loader": "^0.11.2",
      "html-webpack-plugin": "^2.29.0",
      "style-loader": "^0.18.2",
      "webpack": "^3.0.0",
      "xml-loader": "^1.2.1"
    }
  }
  • 命令行执行npm run watch并查看webpack是如何编译你的代码的。你会看到执行完该命令后并不会退出命令行,因为该脚本正在监视你的文件。

  • 现在,在webpack监视你的文件的情况下,我们来移除之前介绍的错误:

src/print.jg

  export default function printMe() {
-   cosnole.log('I get called from print.js!');
+   console.log('I get called from print.js!');
  }
  • 现在保存文件并检查终端控制台。你应该看到webpack重新编译了发生改变的模块!

  • 这种方式的唯一缺点就是你不得不刷新浏览器才能看到改变。如果能自动刷新就更好了,让我们试试webpack-dev-server,它就会自动刷新。

使用 webpack-dev-server

  • webpack-dev-server为你提供一个简单的服务器并且能够热加载。我们来设置一下:
npm install --save-dev webpack-dev-server
  • 修改配置文件以告诉dev 服务器到哪里查找文件:

webpack.config.js

  const path = require('path');
  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const CleanWebpackPlugin = require('clean-webpack-plugin');

  module.exports = {
    entry: {
      app: './src/index.js',
      print: './src/print.js'
    },
    devtool: 'inline-source-map',
+   devServer: {
+     contentBase: './dist'
+   },
    plugins: [
      new CleanWebpackPlugin(['dist']),
      new HtmlWebpackPlugin({
        title: 'Development'
      })
    ],
    output: {
      filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist')
    }
  };
  • 这将告诉webpack-dev-serverlocalhost:8080dist目录提供文件。

  • 让我们添加一个脚本以便轻松启动dev 服务器

package.json

  {
    "name": "development",
    "version": "1.0.0",
    "description": "",
    "main": "webpack.config.js",
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
      "watch": "webpack --watch",
+     "start": "webpack-dev-server --open",
      "build": "webpack"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
      "clean-webpack-plugin": "^0.1.16",
      "css-loader": "^0.28.4",
      "csv-loader": "^2.1.1",
      "file-loader": "^0.11.2",
      "html-webpack-plugin": "^2.29.0",
      "style-loader": "^0.18.2",
      "webpack": "^3.0.0",
      "xml-loader": "^1.2.1"
    }
  }
  • 现在我们从命令行执行npm start命令,就会看到我们的浏览器会自动加载我们的页面。现在如果你改变任何源代码并保存,web 服务器就会在代码编译后自动加载。试一下!

  • webpack-dev-server提供了很多配置项。可以查看文档了解更多

现在你的服务已经启动了,你可能想尝试下 模块热加载

使用 webpack-dev-middleware (中间件)

  • webpack-dev-middleware是一个包装器,它将webpack处理的文件发送到服务器。这在webpack-dev-server内部使用,但它可以作为单独的包提供,以便在需要时允许更多自定义设置。我们将看一个将webpack-dev-middleware与express 服务器**相结合的示例。

  • 首先安装expresswebpack-dev-middleware

npm install --save-dev express webpack-dev-middleware
  • 现在我们需要做一些调整以确保webpack-dev-middleware能够正常运行:

webpack.config.js

  const path = require('path');
  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const CleanWebpackPlugin = require('clean-webpack-plugin');

  module.exports = {
    entry: {
      app: './src/index.js',
      print: './src/print.js'
    },
    devtool: 'inline-source-map',
    plugins: [
      new CleanWebpackPlugin(['dist']),
      new HtmlWebpackPlugin({
        title: 'Output Management'
      })
    ],
    output: {
      filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist'),
+     publicPath: '/'
    }
  };
  • publicPath也将在我们服务器脚本中使用,以确保在http://localhost:3000(我么稍后将指定端口号)上正确提供文件。下一步是设置我们的自定义express 服务器

project

  webpack-demo
  |- package.json
  |- webpack.config.js
+ |- server.js
  |- /dist
  |- /src
    |- index.js
    |- print.js
  |- /node_modules

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);

// Tell express to use the webpack-dev-middleware and use the webpack.config.js
// configuration file as a base.
app.use(webpackDevMiddleware(compiler, {
  publicPath: config.output.publicPath
}));

// Serve the files on port 3000.
app.listen(3000, function () {
  console.log('Example app listening on port 3000!\n');
});
  • 现在添加npm 脚本以方便运行服务器:

package.json

  {
    "name": "development",
    "version": "1.0.0",
    "description": "",
    "main": "webpack.config.js",
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
      "watch": "webpack --watch",
      "start": "webpack-dev-server --open",
+     "server": "node server.js",
      "build": "webpack"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
      "clean-webpack-plugin": "^0.1.16",
      "css-loader": "^0.28.4",
      "csv-loader": "^2.1.1",
      "express": "^4.15.3",
      "file-loader": "^0.11.2",
      "html-webpack-plugin": "^2.29.0",
      "style-loader": "^0.18.2",
      "webpack": "^3.0.0",
      "webpack-dev-middleware": "^1.12.0",
      "xml-loader": "^1.2.1"
    }
  }
  • 现在在控制台执行npm run server,可能会输出如下内容:
Example app listening on port 3000!
webpack built 27b137af6d9d8668c373 in 1198ms
Hash: 27b137af6d9d8668c373
Version: webpack 3.0.0
Time: 1198ms
          Asset       Size  Chunks                    Chunk Names
  app.bundle.js    1.44 MB    0, 1  [emitted]  [big]  app
print.bundle.js    6.57 kB       1  [emitted]         print
     index.html  306 bytes          [emitted]
   [0] ./src/print.js 116 bytes {0} {1} [built]
   [1] ./src/index.js 403 bytes {0} [built]
   [2] ./node_modules/lodash/lodash.js 540 kB {0} [built]
   [3] (webpack)/buildin/global.js 509 bytes {0} [built]
   [4] (webpack)/buildin/module.js 517 bytes {0} [built]
Child html-webpack-plugin for "index.html":
         Asset    Size  Chunks  Chunk Names
    index.html  544 kB       0
       [0] ./node_modules/html-webpack-plugin/lib/loader.js!./node_modules/html-webpack-plugin/default_index.ejs 538 bytes {0} [built]
       [1] ./node_modules/lodash/lodash.js 540 kB {0} [built]
       [2] (webpack)/buildin/global.js 509 bytes {0} [built]
       [3] (webpack)/buildin/module.js 517 bytes {0} [built]
webpack: Compiled successfully.
  • 现在启动浏览器并转到http://localhost:3000,应该看到你的webpack 应用程序运行和起作用了!

如果您想了解更多关于热模块替换工作的内容,我们建议您阅读模块热加载。

调整你的编辑器

  • 当你使用自动编译代码时,你可能在保存文件时遇到问题。一些编辑器有一个“safe write”的特性,它可能会干扰重新编译。

  • 在一些常见的编辑器中禁止该特性:

    • Sublime Text 3: 在用户首选项添加**atomic_save: "false" **。
    • JetBrains IDEs (e.g. WebStorm): 取消 "Use safe write": Preferences > Appearance & Behavior > System Settings
    • Vim: 设置添加:set backupcopy=yes

总结

  • 既然你已经学会了自动编译代码已经启动一个简单的开发服务器,你可以查看下一个教程 模块热加载.

你可能感兴趣的:(webpack 4 入门指南 系列五(开发篇))