美文网首页
webpack 4 使用简析

webpack 4 使用简析

作者: Whyn | 来源:发表于2019-05-05 03:52 被阅读0次

前言

本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。

在开始使用 webpack 前,需要了解 webpack 的四个核心概念:

  • 入口(entry)入口起点(entry point)指示了 webpack 要解析的源码模块,webpack 会解析这些模块并构建出其内部 依赖图,最后将完整的依赖输出到 bundle 文件中。

   可以通过在 webpack 中配置 entry 属性,来指定一个入口起点(或多个入口起点)。默认值为 ./src

单入口配置

// webpack.config.js
module.exports = {
  entry: './path/to/my/entry/file.js'
};

多入口配置

// webpack.config.js
module.exports = {
  entry: {
    pageOne: './src/pageOne/index.js', // 入口1
    pageTwo: './src/pageTwo/index.js', // 入口2
    pageThree: './src/pageThree/index.js' // 入口3
  }
};

更多配置内容,请参考:入口起点

  • 输出(output):output 属性指定 webpack 输出 bundles 路径,以及命名规则。默认值为 ./dist

   output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件,默认值为 ./dist

   可以通过配置 output 字段来配置输出的 bundle 文件:

//webpack.config.js
const path = require('path'); // 使用 nodejs 的 path 库

module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'), // 工程根目录的 dist 文件夹
    filename: 'my-first-webpack.bundle.js' // 输出 bundle 名字
  }
};

更多配置选择,请参考:输出

  • loaderwebpack 本身只能处理 JavaScript 文件,对于那些非 JavaScript 的文件,则可以通过各种相应的 loader 来将其转换成 webpack 能够识别并进行处理的模块。

   比如,在 webpack 打包前,loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件!

   本质上,loader 将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)可以直接引用的模块。

webpack 中, 配置 loader 主要使用以下两个选项:

  • test 属性:标识 loader 要处理的文件类型;
  • use 属性:表示进行转换时,应该使用哪个 loader;
//webpack.config.js
const path = require('path');

const config = {
  output: {
    filename: 'my-first-webpack.bundle.js'
  },
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  }
};

module.exports = config;

上述配置中,指定了 webpack 编译器在遇到 require()import 导入 txt 文件时,先使用 raw-loader 进行转换,然后再打包。

:loader 支持链式传递。一组链式的 loader 将按照相反的顺序执行。loader 链中的第一个 loader 返回值给下一个 loader(简而言之,loader 的执行顺序与配置相反,最后配置的 loader 最先执行)。

更多 loader 的配置,请参考:loader

更多内置 loader,请查看:loaders

更多第三发 loader,请查看:awesome-webpack

  • 插件(plugins):loader 是在打包构建过程中用于处理某些类型的模块转换,而插件的能力更大,其在整个构建过程中起作用,可以执行范围更广的任务,比如打包优化和压缩 bundle 文件,甚至于重新定义环境中的变量。

   这样说吧,loader 就是在构建前对某些特定类型的文件进行预处理,而插件是在构建过程中能做任何事情(应该可以这样认为,loader 其实就是一个小型的插件,其只能对某些特定文件进行预处理。而插件的目的就在于解决 loader 无法处理的事情)。

   想要使用一个插件,你只需要 require() 它,然后把它添加到 plugins 数组中。多数插件可以通过选项(option)自定义配置。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建它的一个实例。

// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件

const config = {
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

module.exports = config;

webpack 提供许多开箱可用的插件!查阅我们的 插件列表 获取更多信息。

更多第三方插件,请查看 awesome-webpack 列表。

更多插件配置信息,请参考:插件(plugins)

安装

  1. 首先安装最新版本的 Node.js

  2. 本地安装 webpack

npm install webpack  --save-dev 
npm install webpack-cli --save-dev 

:也可以全局安装 webpacknpm install --global webpack。但是不推荐。

快速入门

例子:要求在 src/index.js 中为 document.body 添加一个 div 子节点,该 div 子节点内容为:"Hello,Webpack"(要求使用第三方模块 lodash 实现字符串拼接)。最后使用 webpacksrc/index.js 模块内容打包到 dist/index.js 中,dist/index.html 引用该生成的 bundle 实现页面动态添加 div 子节点功能。

实践

  1. 首先创建目录结构,如下所示:
  webpackDemo
+ |- /dist
+   |- index.html
+ |- /src
+   |- index.js
  1. 创建一个 package.json 文件:
npm init -y
  1. 本地安装 webpack
npm install webpack webpack-cli --save-dev
  1. 根目录下创建 webpack 默认配置文件:webpack.config.js,并配置其入口起点为:src/index.js,打包生产的 bundle 文件为:dist/index.js
const path = require('path');

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    filename: 'index.js',
    path: path.resolve(__dirname, 'dist')
  }
};
  1. 安装 lodash
npm install lodash --save-dev
  1. 编写 src/index.js 代码:
import _ from 'lodash'

function createDiv(){
    let div = document.createElement('div');
    div.innerHTML = _.join(['Hello',',','Webpack']);
    return div;
}

document.body.appendChild(createDiv());
  1. 进行打包,打包完成后即可看到 dist/index.js 生成:
npx webpack
  1. 手动将生成的 dist/index.js 引入到 dist/index.html 中,打开浏览器,即可看到效果:
<!DOCTYPE html>
<html>
    <head>
        <title>Webpcak Demo</title>
    </head>
    <body>
        <script src="index.js"></script>
    </body>
</html>

一些有用配置

  • 模式(mode):提供 mode 配置选项,区分生成环境,告知 webpack 使用相应模式的内置优化。其选择有两个值可选:developmentproduction
module.exports = {
  mode: 'production'
};
  • 基础配置:生产环境 + 入口 + 出口
// webpack.config.js
var path = require('path');

module.exports = {
  mode: 'development',
  entry: './foo.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'foo.bundle.js'
  }
};
  • resolve.alias:创建 importrequire 的别名,来确保模块引入变得更简单。例如,一些位于 src/ 文件夹下的常用模块:
// webpack.config.js
module.exports = {
  resolve: {
    alias: {
      Utilities: path.resolve(__dirname, 'src/utilities/'),
      Templates: path.resolve(__dirname, 'src/templates/')
    }
  }
}

像未配置前需要使用全路径或相对路径引入:

// index.js
import Utility from '../../utilities/utility';

在配置后,就可以使用别名进行导入:

// index.js
import Utility from 'Utilities/utility'; // 注意使用的是别名:Utilities
  • watch:webpack 可以监听文件变化,当它们修改后会重新编译。watch 默认为关闭。
watch: true

还可以通过 watchOptions 来进一步控制 watch 模式的选项:

watchOptions: {
  aggregateTimeout: 300, // 文件更改后,300毫秒后进行重新构建
  poll: 1000, // 轮询时间,每 1s 进行一次检测
  ignored: /node_modules/  // 不监听 node_modules 目录
}
  • 外部扩展(externals):防止将某些 import 的包(package)打包到 bundle 中,而是在运行时(runtime)再去从外部获取这些扩展依赖(external dependencies)。

   例如,从 CDN 引入 jQuery,而不是把它打包:

<!-- index.html -->
<script
  src="https://code.jquery.com/jquery-3.1.0.js"
  integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
  crossorigin="anonymous">
</script>
// webpack.config.js
externals: {
  jquery: 'jQuery'
}

这样就剥离了那些不需要改动的依赖模块,换句话,下面展示的代码还可以正常运行:

import $ from 'jquery';
$('.my-element').animate(...);

像上述配置了 jquery 为外部依赖后,webpack 编译器在遇到:import $ from 'jquery'; 时,就知道了应该排除掉 jquery 模块,不将其打包进 bundle 中。

// webpack.config.js
module.exports = {
  target: 'node' // 生成服务器端代码
};

如果想同时生成多个 Target,可以如下配置:

// webpack.config.js
var path = require('path');
var serverConfig = {
  target: 'node',    // 生成服务器端代码
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'lib.node.js'
  }
  //…
};

var clientConfig = {
  target: 'web', // <=== 默认是 'web',可省略
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'lib.js'
  }
  //…
};

module.exports = [ serverConfig, clientConfig ]; // 导出两个 bundle

管理资源

安装

npm install style-loader css-loader --save-dev 

配置

 const path = require('path');

  module.exports = {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
    },
+   module: {
+     rules: [
+       {
+         test: /\.css$/,
+         use: [
+           'style-loader',
+           'css-loader'
+         ]
+       }
+     ]
+   }
  };

使用

  1. 现在 src/ 目录下新建一个 style.css 文件:
// style.css
.container {
    color: red;
}
  1. 修改入口文件:src/index.js
import _ from 'lodash';
+ import './style.css'

function createDiv(){
    let div = document.createElement('div');
    div.innerHTML = _.join(['Hello','Webpack'],',');
+    div.classList.add('container')
    return div;
}

document.body.appendChild(createDiv());
  1. 最后重新打包即可看到效果:npx webpack
  • 抽离 CSS 文件为单独文件:前面使用 style-loader 最终会将 css 样式注入到页面的 <head> 内的 style 节点中,即为内部样式表。我们更希望使用的是外部样式表,即通过 <link> 标签进行引入,那么通过使用 mini-css-extract-plugin 插件即可实现。

安装

npm install mini-css-extract-plugin --save-dev 

配置


const path = require('path');
+ const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV !== 'production'; // 判断当前环境是开发环境还是 部署环境,主要是 mode属性的设置值。

module.exports = {
  module: {
    rules: [
+      {
+        test: /\.(sa|sc|c)ss$/,
+        use: [MiniCssExtractPlugin.loader, 'css-loader']
+      },
    ]
  },
+  plugins: [
+    new MiniCssExtractPlugin({
+      filename: devMode ? '[name].css' : '[name].[hash].css', // 设置最终输出的文件名
+      chunkFilename: devMode ? '[id].css' : '[id].[hash].css'
+    })
+  ]
};

使用:重新打包后,可在浏览器查看是否以外部链接引入样式表。

:由于抽取了样式,因此不再使用 style-loader 注入到 html 中了。

安装

npm install sass-loader node-sass webpack --save-dev

配置

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/,
+        use: [MiniCssExtractPlugin.loader, 'css-loader',sass-loader]
      },
    ]
  },
};

安装

npm install file-loader  --save-dev 

配置

const path = require('path');

  module.exports = {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
    },
    module: {
      rules: [
        {
          test: /\.css$/,
          use: [
            'style-loader',
            'css-loader'
          ]
        },
+       {
+          test: /\.(png|svg|jpg|gif|jpeg|ico)$/,
+         use: [
+           'file-loader'
+         ]
+       }
      ]
    }
  };

使用:只需向项目中增加一张图片。比如,在 style.css 中,引入一张图片:

.container {
    width: 400px;
    height: 400px;
    color: red;
    background: url('../static/img/horse.png');
}

最后,重新打包一下即可看到效果:npx webpack

安装

npm install image-webpack-loader --save-dev

配置

 const path = require('path');

  module.exports = {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
    },
    module: {
      rules: [
        {
          test: /\.css$/,
          use: [
            'style-loader',
            'css-loader'
          ]
        },
        {
          test: /\.(png|svg|jpg|gif|jpeg|ico)$/,
          use: [
            'file-loader',
+           {
+             loader: 'image-webpack-loader',
+             options: {
+               mozjpeg: {
+                 progressive: true,
+                 quality: 65
+               },
+               optipng: {
+                 enabled: false,
+               },
+               pngquant: {
+                 quality: '65-90',
+                 speed: 4
+               },
+               gifsicle: {
+                 interlaced: false,
+               },
+               webp: {
+                 quality: 75
+               }
+             }
+           },
          ]
        }
      ]
    }
  };

使用:重新打包一下,可以看到生成一张已被压缩的图片。

安装

npm install url-loader --save-dev

配置

module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|svg|jpg|gif|jpeg|ico|woff|woff2|eot|ttf|otf)$/,
        use: [
+          {
+            loader: 'url-loader', // 根据图片大小,把图片优化成base64
+            options: {
+              limit: 10000  // 图片小于 10000 字节时,进行 base64 编码
+            }
+          },
          {
            loader: 'image-webpack-loader', // 先进行图片优化
            options: {
              mozjpeg: {
                progressive: true,
                quality: 65
              },
              optipng: {
                enabled: false
              },
              pngquant: {
                quality: '65-90',
                speed: 4
              },
              gifsicle: {
                interlaced: false
              },
              webp: {
                quality: 75
              }
            }
          }
        ]
      }
    ]
  }
};

使用:重新打包后,只要图片小于 10000 字节的,就会被转换成 base64 编码的 DataURL。

file-loaderurl-loader 可以接收并加载任何文件,然后将其输出到构建目录。这就是说,我们可以将它们用于任何类型的文件,包括字体。

管理输出

前面的操作我们都是手动地对 index.html 文件进行管理,但随着项目的增大,手动管理方式将繁琐且容易出错,因此急需一个自动注入资源的方法,这种操作可以通过插件进行完成。

  • 自动注入资源:可以使用 html-webpack-plugin 将打包生成的 bundle 自动注入到 index.html 中。

安装

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

配置

// webpack.config.js
const path = require('path');
+ const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'development',
  entry: {
+    app: './src/index.js' // 为入口起点增加命名
  },

  output: {
    filename: '[name]-[hash].js',
    path: path.resolve(__dirname, 'dist')
  },
+  plugins: [
+    new HtmlWebpackPlugin({
+      title: 'Output Management', // 默认值:Webpack App
+      filename: 'index.html', // 默认值: 'index.html'
+      template: path.resolve(__dirname, 'src/index.html'), // 以 src/index.htm 为模板
+      minify: {
+        collapseWhitespace: true,
+        removeComments: true,
+        removeAttributeQuotes: true // 移除属性的引号
+      }
+    })
+  ]
};

使用:安装上述配置,打包完成后,html-webpack-plugin 插件就会自动把生成的 js 文件插入到 dist/index.html 文件中。

  • 清理 /dist 文件夹:通常,在每次构建前清理 /dist 文件夹,是比较推荐的做法,因此只会生成用到的文件。需要用到插件 clean-webpack-plugin

安装

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

配置


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

module.exports = {
  mode: 'development',
  entry: {
    app: './src/index.js'
  },

  output: {
    filename: '[name]-[hash].js',
    path: path.resolve(__dirname, 'dist')
  },
  plugins: [
+    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
    ...
    })
  ]
};

使用:上述配置完成后,以后每次打包,/dist 目录都会先进行清理,打包后就只生成需要使用到的文件了。

  • JS 启用 babel 转码:虽然现代的浏览器已经兼容了 96% 以上的 ES6 的语法了,但是为了兼容老式的浏览器(IE8、9)我们需要把最新的 ES6 的语法转成 ES5 的。使能该功能需要使用 babel

安装

npm install -D babel-loader @babel/core @babel/preset-env webpack

配置

module: {
  rules: [
    {
      test: /\.m?js$/,
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env']
        }
      }
    }
  ]
}

使用:经过上述配置后,就可以在入口文件中使用 ES6 语法,打包后,该 ES6 语法内容就会被转换成 ES5 语法内容。

  • ESLint校验代码格式规范:需要 eslint 支持。

安装

npm install eslint --save-dev
npm install eslint-loader --save-dev

# 以下是用到的额外的需要安装的eslint的解释器、校验规则等
npm i -D babel-eslint standard

配置

  1. webpack 配置文件进行配置:

module.exports = {
  module: {
    rules: [
      {
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env']
            }
          },
+          {
+            loader: 'eslint-loader',
+            options: {
+              // eslint options (if necessary)
+              fix: true
+            }
+          }
        ]
      },
};
  1. 项目根目录下创建一个文件:.eslintrc.js。往里面写入以下配置:
// .eslintrc.js
// https://eslint.org/docs/user-guide/configuring
module.exports = {
  root: true,
  parserOptions: {
    parser: 'babel-eslint'
  },
  env: {
    browser: true
  },
  extends: [
    // https://github.com/standard/standard/blob/master/docs/RULES-en.md
    'standard'
  ],
  globals: {
    NODE_ENV: false
  },
  rules: {
    // allow async-await
    'generator-star-spacing': 'off',
    // allow debugger during development
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    // 添加,分号必须
    semi: ['error', 'always'],
    'no-unexpected-multiline': 'off',
    'space-before-function-paren': ['error', 'never'],
    // 'quotes': ["error", "double", { "avoidEscape": true }]
    quotes: [
      'error',
      'single',
      {
        avoidEscape: true
      }
    ]
  }
};
  1. 项目根目录下创建一个文件:.eslintignore。该文件配置要忽略 eslint 检测的目录:
/dist/
/node-modules/
# 忽略根目录的 js 文件(即配置文件)
/*.js

开发环境搭建

在开发过程中,我们编写的源代码一般有多个,最后交由 webpack 打包成单独一个 bundle。因此,如果出现错误,错误显示在 bundle 中,就无法直接定位到我们自己的错误代码中。所以,在开发环境(development)中,需要对 webpack 进行一些配置,方便我们进行开发。

  • 使用 source map:为了更容易地追踪错误和警告,JavaScript 提供了 source map 功能,将编译后的代码映射回原始源代码。如果一个错误来自于 b.js,source map 就会明确的告诉你。
    配置:开启 source map
module.exports = {
    devtool: 'inline-source-map',
};
  • 使用观察模式:每次我们修改源码后,都需要使用 npx webpack 进行手动打包,不免繁琐了点。可以通过配置 webpack "watch" 自动监视文件更改,自动进行编译打包。
    配置:启动 "watch" 的方法为控制台输入:npx webpack --watch,也可以将该命令配置到 package.jsonscripts 中,启动一个脚本命令:
// package.json
{
  ···
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
+    "watch": "npx webpack --watch"
  },
  ···
}

使用:控制台输入:npm run watch

  • 使用 webpack-dev-server:webpack "watch" 可以自动进行打包,但是浏览器端我们还是需要手动进行刷新才能看到修改效果。如果我们也想让浏览器实时监测文件修改,自动刷新,则可以使用 webpack-dev-server。

安装

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

配置

module.exports = {
    devServer: {
        contentBase: './dist'  // 监听目录变化,实时重载
    },
};

使用:通过在 package.json 中配置一个脚本命令进行启动:npm run hotload

// package.json
{
  ···
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
    "watch": "npx webpack --watch",
+    "hotload": "webpack-dev-server --open"
  },
  ···
}

生产环境搭建

在生产环境(production)中,我们的目标是倾向于生成更小的 bundle,更轻量的 source map,以及更优化的资源,以改善加载时间。
因此,可通过以下配置来输出更好匹配生产环境的 bundle。

安装

npm i -D optimize-css-assets-webpack-plugin

配置

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
+ const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = {
+  mode: 'production',
+  optimization: {
+    minimizer: [new OptimizeCSSAssetsPlugin({})]
+  },
...
};
  • 压缩 JavaScript:需要的插件:uglifyjs-webpack-plugin,此插件只在 mode: ’production’ 下起作用。

安装

npm i -D uglifyjs-webpack-plugin

配置

+ const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
  mode: 'production',
  optimization: {
    minimizer: [
+      new UglifyJsPlugin({
+        cache: true,
+        parallel: true,
+        sourceMap: true // set to true if you want JS source maps
+      }),
      new OptimizeCSSAssetsPlugin({})
    ]
  }
};

区分开发环境和生产环境

开发环境(development)和生产环境(production)的构建目标差异很大。两者的构建目标既存在相同部分,也存在不同之处。因此,通常会为每个环境编写 彼此独立的 webpack 配置,对于两者皆有的配置,则抽取到一个公共的配置文件中即可。这种分文件配置方法可通过插件 webpack-merge 完成。

安装

npm install webpack-merge --save-dev

配置:具体配置详情如下:

  • 新建一个文件:webpack.common.js。作为开发环境和生产环境公共配置文件:
// webpack.common.js
const path = require('path');
// 清理 /dist
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
  entry: {
    app: './src/index.js'
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env']
            }
          },
          {
            loader: 'eslint-loader',
            options: {
              fix: true
            }
          }
        ]
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 10000
            }
          }
        ]
      },
      {
        test: /\.(png|svg|jpg|gif|jpeg|ico)$/,
        use: [
          {
            loader: 'url-loader', // 根据图片大小,把图片优化成base64
            options: {
              limit: 10000
            }
          },
          {
            loader: 'image-webpack-loader', // 先进行图片优化
            options: {
              mozjpeg: {
                progressive: true,
                quality: 65
              },
              optipng: {
                enabled: false
              },
              pngquant: {
                quality: '65-90',
                speed: 4
              },
              gifsicle: {
                interlaced: false
              },
              webp: {
                quality: 75
              }
            }
          }
        ]
      }
    ]
  },
  plugins: [new CleanWebpackPlugin()]
};
  • 新建一个文件:webpack.dev.js。作为开发环境的配置文件:
const path = require('path');
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
// 注入资源到 html
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 抽离 CSS 文件为单独文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// merge 第二参数的配置会覆盖第一个参数相同的配置
module.exports = merge(common, {
  mode: 'development',
  // 使能 source map
  devtool: 'inline-source-map',
  // 使能 webpack-dev-server,浏览器自动重载
  devServer: {
    contentBase: './dist' // 监听目录内容改变
  },
  watchOptions: {
    // 监视文件相关的控制选项
    poll: true, // webpack 使用文件系统(file system)获取文件改动的通知。在某些情况下,不会正常工作。例如,当使用 Network File System (NFS) 时。Vagrant 也有很多问题。在这些情况下,请使用轮询. poll: true。当然 poll也可以设置成毫秒数,比如:  poll: 1000
    ignored: /node_modules/, // 忽略监控的文件夹,正则
    aggregateTimeout: 300 // 默认值,当第一个文件更改,会在重新构建前增加延迟
  },
  module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              sourceMap: true
            }
          },
          {
            loader: 'sass-loader',
            options: {
              sourceMap: true
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'Development',
      filename: 'index.html', // 默认值: 'index.html',
      template: path.resolve(__dirname, 'src/index.html'),
      minify: {
        collapseWhitespace: false,
        removeComments: false,
        removeAttributeQuotes: true // 移除属性的引号
      }
    }),
    new MiniCssExtractPlugin({
      filename: '[name].css', // 设置最终输出的文件名
      chunkFilename: '[id].css'
    })
  ]
});
  • 新建一个文件:webpack.prod.js。作为生产环境的配置文件:
const path = require('path);
const merge = require('webpack-merge');
// 压缩 js 文件
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const common = require('./webpack.common.js');
// 注入资源到 html
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 压缩 CSS
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
// 压缩 JS
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
// 抽离 CSS 文件为单独文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

// merge 第二参数的配置会覆盖第一个参数相同的配置
module.exports = merge(common, {
  mode: 'production',
  optimization: {
    minimizer: [
      new UglifyJsPlugin({
        cache: true,
        parallel: true,
        sourceMap: true // set to true if you want JS source maps
      }),
      new OptimizeCSSAssetsPlugin({})
    ]
  },
  module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              sourceMap: true
            }
          },
          {
            loader: 'sass-loader',
            options: {
              sourceMap: true
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new UglifyJSPlugin(),
    new HtmlWebpackPlugin({
      title: 'Production', // 默认值:Webpack App
      filename: 'index.html', // 默认值: 'index.html'
      template: path.resolve(__dirname, 'src/index.html'),
      minify: {
        collapseWhitespace: true,
        removeComments: true,
        removeAttributeQuotes: true // 移除属性的引号
      }
    }),
    new MiniCssExtractPlugin({
      filename: '[name].[hash].css', // 设置最终输出的文件名
      chunkFilename: '[id].[hash].css'
    })
  ]
});
  • 最后,在 package.json 中配置如下脚本,可分别启动开发环境和生产环境:
// package.json
{
  ···
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "watch": "npx webpack --watch",
    "hotload": "webpack-dev-server --open",
+    "start": "webpack-dev-server --open --config webpack.dev.js",
+    "build": "webpack --config webpack.prod.js"
  },
  ···
}

通过 npm run start 启动开发环境,
通过 npm run build 启动生产环境。

参考

相关文章

网友评论

      本文标题:webpack 4 使用简析

      本文链接:https://www.haomeiwen.com/subject/vlvxoqtx.html