[ webpack4 ] 配置属于自己的打包系统教程(最终篇)—— 环境配置篇

GitHub 完整配置文件地址: https://github.com/yhtx1997/w...

由于篇幅过长分三次发布,建议按顺序看
[ webpack4 ] 配置属于自己的打包系统教程(一)—— 基础配置篇
[ webpack4 ] 配置属于自己的打包系统教程(二)—— 资源配置篇
[ webpack4 ] 配置属于自己的打包系统教程(最终篇)—— 环境配置篇

环境配置篇

主要内容

  • 开发环境生产环境分离
  • 实时预览
  • webpack-dev-server 其他常用
  • 代码复用处理

开发环境和生产环境

到了这一步,该讲讲开发环境模式和生产环境模式了

  • 开发环境是自己开发时用的,需要有实时编译功能、模块热替换功能(更新文件不用完全更新页面)、错误提示到具体哪个文件几行
  • 生产环境是放到线上给用户使用的,需要代码压缩功能

配置代码组件化

我们先把之前配置好的 webpack 配置文件改下名,改名 webpack.common.js ,意思是开发环境和生产环境都需要的,将代码压缩之类的挪到生产配置下
之后安装 webpack-merge ,官方推荐的是为每个环境写单独的 webpack 文件

虽然有简单的方法实现但是依然推荐写单独的配置文件,因为在这样的配置方式你可以更清楚你自己在做什么,还可以让你的配置更加个性(自定义)

安装 webpack-merge

npm install webpack-merge -D

新建开发环境配置

我们新建一个 js 文件,命名为 webpack.dev.js ,添加如下代码

const merge = require('webpack-merge');//合并配置
const common = require('./webpack.common.js');//引入公共配置

 module.exports = merge(common, {
    mode: 'development',//声明是开发环境
     //关于 dev 的配置
 })

新建开发环境配置

我们新建一个 js 文件,命名为 webpack.prod.js

添加如下代码

const merge = require('webpack-merge');//合并配置
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');//用来压缩 js 代码
const common = require('./webpack.common.js');//引入公共配置

module.exports = merge(common, {
    mode: 'production',//声明是生产环境
    //关于 prod 的配置
});

开发环境

实时预览

跟着配置并操作的小伙伴可能发现了,每次修改后都需要手动在命令行输入命令,并且还要刷新浏览器才能看到最新的效果

那么现在来解决这两个问题,方法就是使用 webpack-dev-server

安装
npm install webpack-dev-server -D
配置
  • 实时预览
  • 自定义请求代理
  • 自定义 ip 及端口
  • 注:使用 webpack-dev-server 并不会编译到本地文件,而是放到内存中
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const path = require('path');
const webpack = require('webpack');

 module.exports = merge(common, {
    mode: 'development',
    devServer: {
        contentBase: path.join(__dirname, 'dist'),//预览的目录,写出口目录的绝对路径
        hot: true,//模块热更新
        host: 'localhost',//默认值 也可以改为 127.0.0.1 或者其他
        port: 8080,
        proxy: {
            '/api': 'http://localhost:3000'//请求到 /api/users 现在会被代理到请求 http://localhost:3000/api/users
        }

    }
 })

接下来加入错误提示以及将生成 HTML 的代码从公共配置( webpack.common.js )拿到这里

因为开发和生产有些许不一样,我又不知道怎样简单配置,所以开发环境和生产环境我都会放一个生成 HTML 的代码

生产环境

  • 每次打包都要清理掉旧文件
  • 所有代码都要进行压缩
  • 重复的 js 代码,需要只有一个就好

文件清理

从公共配置( webpack.common.js )将之前文件清理的代码拿过来放到这里

const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = merge(common, {
    mode: 'production',
    plugins: [
        new CleanWebpackPlugin(['dist']),
        new HtmlWebpackPlugin({
            title: '2048',
            template: './src/index.html',
            minify: true,//HTML 代码压缩
            hash: true
        }),
    ],
})

代码压缩

先安装压缩代码的插件

npm install uglifyjs-webpack-plugin -D 
npm install optimize-css-assets-webpack-plugin -D
  • uglifyjs-webpack-plugin 是 js 压缩插件
  • optimize-css-assets-webpack-plugin 是推荐和
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");

复用代码分离

假设需要使用 jQuery 来辅助开发,我在 a.js b.js 两个文件都引入了 jQuery ,将 a.js b.js 打包成 a.min.js b.min.js ,这时看他们的体积会比原来大很多,且 a 和 b 的代码中都包含完整的 jQuery 代码

为了解决这种情况,我们需要将 jQuery 这种复用的代码分离到单独的文件

在将环境设置为生产环境时默认开启了很多功能,其中 SplitChunksPlugin 就是用于避免重复依赖的

在我们不配置时 默认配置是这样的

optimization: {
    splitChunks: {
      chunks: 'async', 
      minSize: 30000,
      minChunks: 1,
    }
  }
  • chunks: 表示哪些代码需要优化,有三个可选值:initial(初始块)、async(按需加载块)、all(全部块),默认为async 改成 all 支持所有的
  • minSize: 这个文件最少是多少才去优化,默认为 30000 实际测试是文件大于 30 kb,在 31kb时开始优化
  • minChunks: 最少引用几次才去优化,默认为1 实际测试为在只引用一次的情况不优化,只有大于它才优化
  • 注: 还有其他属性个人感觉不常用就没写,了解更多可以看这里

最终代码汇总

最终公共配置 webpack.common.js 代码如下

const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
    entry: {
        512:'./src/js/512.js',
        1024:'./src/js/1024.js',
        2048:'./src/js/2048.js',
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: "css/[name].css"
        })
    ],
    output: {
        filename: "js/[name].js",
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                  loader: 'babel-loader',
                  options: {
                    presets: ['@babel/preset-env']
                  }
                }
              },
              {
                test: /\.scss$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    'postcss-loader',
                    'sass-loader',
                ]
            },
            {
                test: /\.(png|svg|jpg|gif)$/,
                use: [
                    'file-loader'
                ]
            },
            {
                test: /\.(woff|woff2|eot|ttf|otf)$/,
                use: [
                    'file-loader'
                ]
            },
            {
                test: /\.(csv|tsv)$/,
                use: [
                    'csv-loader'
                ]
            },
            {
                test: /\.xml$/,
                use: [
                    'xml-loader'
                ]
            }
        ]
    },

}

最终开发环境 webpack.dev.js 代码如下

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

 module.exports = merge(common, {
    mode: 'development',
    plugins: [
        new HtmlWebpackPlugin({
            title: '2048',
            template: './src/index.html',
            minify: false,
            hash: true
        })
    ],
    devtool: 'inline-source-map',
    devServer: {
        contentBase: path.join(__dirname, 'dist'),
        host: 'localhost',
        port: 8080,
        proxy: {
            '/api': 'http://localhost:3000'
        }

    }
 })

最终生产环境 webpack.prod.js 代码如下

const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = merge(common, {
    mode: 'production',
    plugins: [
        new CleanWebpackPlugin(['dist']),
        new HtmlWebpackPlugin({
            title: '2048',
            template: './src/index.html',
            minify: true,
            hash: true
        }),
    ],
    optimization: {
        splitChunks: {
            chunks: 'all'
        },
        minimizer: [
            new UglifyJsPlugin({
                cache: true,
                parallel: true,
                sourceMap: true 
            }),
            new OptimizeCSSAssetsPlugin({})
        ],
    }
});

npm 项目配置代码 package.json 代码如下

{
  "name": "2048",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "main": "index.js",
  "scripts": {
    "dev": "webpack-dev-server --open --config webpack.dev.js",
    "build": "webpack --config webpack.prod.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "webpack": "^4.28.3"
  },
  "devDependencies": {
    "@babel/core": "^7.2.2",
    "@babel/preset-env": "^7.2.3",
    "autoprefixer": "^9.4.3",
    "babel-loader": "^8.0.4",
    "clean-webpack-plugin": "^1.0.0",
    "css-loader": "^2.1.0",
    "csv-loader": "^3.0.2",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "file-loader": "^3.0.1",
    "html-webpack-plugin": "^3.2.0",
    "mini-css-extract-plugin": "^0.5.0",
    "node-sass": "^4.11.0",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "postcss": "^7.0.7",
    "postcss-loader": "^3.0.0",
    "sass-loader": "^7.1.0",
    "style-loader": "^0.23.1",
    "uglifyjs-webpack-plugin": "^2.1.1",
    "webpack-cli": "^3.1.2",
    "webpack-dev-server": "^3.1.14",
    "webpack-merge": "^4.1.5",
    "xml-loader": "^1.2.1"
  }
}

相关推荐