文章注重过程描述,不具备技术深度。

系列文章地址:

一、描述

之前的版本中已经支持了如下:

  • 基础的输入输出
  • css / less
  • 图片打包

并且有了基本的目录结构,但是目录结构比较混乱,还是很初级的阶段,这篇文章的目的是支持 webpack-dev-serverhtml-webpack-plugin 以及 ES2015.vue

二、html-webpack-plugin

之前是我们自己写了一个 index.html,而且是手动写了 <script src="./build.js" /> 来引入 bundle,而且 live-server 也依赖这个 html 文件。

这很痛苦,缺点明显,每次构建名字改了之后,也得改 script 名字。

html-webpack-plugin 的文档地址:https://webpack.docschina.org/plugins/html-webpack-plugin/

html-webpack-plugin 目的是通过一个 html 模板,自动注入打包后的 js bundle。

修改后的 index.html 移到了 ./publish/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>webpack vue</title>
</head>
<body>
  <div id="app"><!--  --></div>
</body>
</html>

引入 html-webpack-plugin,并在 webpack.config.js 中配置:

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

关于 webpack 的插件使用这里不再重复,通过 template 配置选项可以指定模板位置。

  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html'
    }),
  ],

可能会遇到下面的报错:

1.jpg

这是因为 html-webpack-plugin 依赖了 webpack/lib/node/NodeTemplatePlugin,但是没有安装 webpack,因此需要安装 webpack:

yarn add -D webpack

需要注意的是,html-webpack-plugin 也会直接打包出 html 文件到 output 的目录,并不会直接使用 html 文件。

三、webpack-dev-server

文档地址:https://webpack.docschina.org/configuration/dev-server/

到目前位置都是通过 live-server 进行本地服务器,监听的实际上是 dist 夹,但是热重载都是靠文件变更, 如果文件变更了,就会刷新,并不会热重载。

webpack-dev-server 对于开发阶段的热重载是非常有价值的。

安装依赖:

yarn add -D webpack-dev-server webpack-cli

webpack-dev-server 依赖 webpack-cli 的 API,因此需要安装 webpack-cli

然后在 webpack.config.js 中配置 devServer 的内容:

  devServer: {
    contentBase: path.join(__dirname, 'dist'), // 监听目录
    compress: true, //  gzip 压缩
    port: 8080, // 端口
    hot: true, // 热重载
    inline: true, // 内联模式 通过内置脚本监听热重载
    open: true, // 打开浏览器
  }

6个常用的配置参数如上,也都注释了什么意思,更多的配置参数可以从文档中看。

如果要完全开启 热重载,只配置 hot: true 不够,需要使用 webpack 的内置插件 HotModuleReplacementPlugin

使用内置 plugin 需要引入 webpack:const webpack = require('webpack')

  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html'
    }),
    new webpack.HotModuleReplacementPlugin(),
  ],

当然,如果是在命令行中使用了 webpack-dev-server --hot 的形式,则会自动的注入这个插件,不需要手动指定。

四、ES2015的语法及API 的 polyfill

语法编译

支持 ES2015 语法编译以及 polyfill 在旧浏览器的运行(IE9+)。

首先是 Babel 的语法支持,webpack 4.x 已经建议使用 Babel 8.x,安装 dev 依赖:

yarn add @babel/core @babel/plugin-transform-runtime @babel/preset-env babel-loader -D

因为使用了 @babel/plugin-transform-runtime 所以还需要使用 @babel/runtime:

yarn add @babel/runtime

webpack.config.js 的配置:

{
  test: /\.(js)$/,
  exclude: /(node_modules)/,
  use:{
    loader: 'babel-loader',
    options: {
      presets: ['@babel/preset-env'],
      plugins: ['@babel/transform-runtime']
    }
  }
}

需要除去 node_module 目录,避免每次都特别慢。

API polyfill

一般为了省事,会直接使用完整的 polyfill,而不会再去单独引入 polyfill 的包。

@babel/polyfill 是 babel 提供的完整的 API 的 polyfill,文档地址: https://babeljs.io/docs/en/babel-polyfill/

yarn add @babel/polyfill

如果通过 import 或者 require 的方式引入 polyfill,则需要在入口文件的最顶层, 保证在其他依赖的前置引入 @babel/polyfill

bundle 过大问题

如果 import 了完整的 @babel/polyfill ,代码会上涨 100 多K:

3.jpg

2.jpg

因此一般还是单独打包 polyfill 或者是直接在 html 中引入 polyfill,通过 CDN 来减少 bundle 大小:

<script src="https://cdn.bootcss.com/babel-polyfill/7.2.5/polyfill.min.js"></script>  

五、webpack.config.js 配置内容

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

module.exports = {
  mode: 'development',
  watch: true,
  entry: {
    'main': './src/main.js'
  },
  output: {
    path: path.resolve('./dist/'),
    filename: '[name].bundle.js'
  },
  module: {
    rules: [{
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader']
      },
      {
        test: /\.(png|jpg|gif|svg|webp|jpeg)$/,
        use: [{
          loader: 'file-loader',
          options: {
            name: '[name]-[hash].[ext]',
            outputPath: 'images/',
            publicPath: 'images/',
          }
        }]
      },
{
  test: /\.(js)$/,
  exclude: /(node_modules)/,
  use:{
    loader: 'babel-loader',
    options: {
      presets: ['@babel/preset-env'],
      plugins: ['@babel/transform-runtime']
    }
  }
}
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html'
    }),
    new webpack.HotModuleReplacementPlugin(),
  ],
  devServer: {
    contentBase: path.join(__dirname, 'dist'), // 监听目录
    compress: true, //  gzip 压缩
    port: 8080, // 端口
    hot: true, // 热重载
    inline: true, // 内联模式 通过内置脚本监听热重载
    open: true, // 打开浏览器
  }
}

六、package.json

{
  "scripts": {
    "watch": "webpack --config ./webpack.dev.config.js",
    "build": "webpack --config ./webpack.prod.config.js",
    "server": "webpack-dev-server",
    "start": "webpack-dev-server --config ./webpack.dev.config.js && webpack --config ./webpack.dev.config.js "
  },
  "dependencies": {
    "@babel/polyfill": "^7.2.5",
    "@babel/runtime": "^7.2.0",
    "vue": "^2.5.21"
  },
  "devDependencies": {
    "@babel/core": "^7.2.2",
    "@babel/plugin-transform-runtime": "^7.2.0",
    "@babel/preset-env": "^7.2.3",
    "babel-loader": "^8.0.5",
    "css-loader": "^2.1.0",
    "file-loader": "^3.0.1",
    "html-webpack-plugin": "^3.2.0",
    "less-loader": "^4.1.0",
    "style-loader": "^0.23.1",
    "webpack": "^4.28.1",
    "webpack-cli": "^3.2.1",
    "webpack-dev-server": "^3.1.14"
  }
}

七、Github 地址

分支:dev/20190110

地址:https://github.com/postbird/webpack4.x-build-vue-0-1-demo/tree/dev/20190110