从0配置一个webpack5+vue3的项目

782 阅读2分钟

背景

手动配置一个webpack5项目吧,webpack5 + vue3 + babel + TypeScript + eslint + stylelint

下面可能写的不是很全, 这是我的github仓库 learning-webpack5 可以作为参考

安装

webpack

npm i webpack@5.44.0 webpack-cli@4 webpack-manifest-plugin webpack-merge -D
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
const { merge: webpackMerge } = require('webpack-merge');
const baseConfig = require('./base.js');

module.exports = webpackMerge(baseConfig, {
  plugins: [
    new WebpackManifestPlugin({
        publicPath: '',
        filter: function (FileDescriptor) {
            return FileDescriptor.isChunk;
        }
    })
  ]
})

webpack-dev-server

npm install webpack-dev-server@4 -D

注意,webpack5版本下的,启动服务的命令已经不再是 webpack-dev-server --config ./build/dev.js

而是使用新的命令 webpack serve --config ./build/dev.js

module.exports = {
  devServer: {
    host: '::',
    port: 8087, /* 端口号 */
    compress: true, /* 启用 gzip compression */
    open: [`http://localhost:${server.port}`], /* 告诉 dev-server 在服务器已经启动后打开浏览器 */
    hot: true, /* 启用 webpack 的 热模块替换 */
    client: {
        progress: true, /* 在浏览器中以百分比显示编译进度 */
        overlay: {
            errors: true,
            warnings: false,
        }, /* 当出现编译错误或警告时,在浏览器中显示全屏覆盖 */
    },
    /* 
      提供在服务器内部执行所有其他中间件之前执行自定义中间件的能力
      这可以用来定义自定义处理程序
    */
   /* 
      我是配置了一个多页面的应用,所以加了这个,正常不需要加这个
   */
    onBeforeSetupMiddleware: function (devServer) {
        if (!devServer) {
            throw new Error('webpack-dev-server is not defined');
        }
        devServer.app.get('/', (req, res) => {
            var resHtml = `<!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <title>index</title>
            </head>
            <body>
                <ul>`;
            for (let key in entries) {
                if (key.indexOf('\/commons\/') === -1) {
                    resHtml += `<li><a href="${key}.html">${key}.html</a></li>`;
                }
            }
            resHtml += `</ul>
            </body>
            </html>`;
            res.send(resHtml);
        });
    },
    onListening: function (devServer) {
        if (!devServer) {
            throw new Error('webpack-dev-server is not defined');
        }
    }
  }
}

ES6转ES5

npm i babel-loader @babel/core @babel/preset-env -D

npm install @babel/plugin-transform-runtime -D
npm install  @babel/runtime @babel/runtime-corejs3 --save
// .babelrc
{
    "presets": [
        [
            "@babel/preset-env",
            {
                "targets": {
                    "browsers": ["> 1%", "last 2 versions", "not ie <= 8", "Android >= 4.4"]
                }
            }
        ]
    ],
    "plugins": [
        ["@babel/plugin-transform-runtime", {
            "corejs": 3
        }]
    ]
}

// loader
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: file => (
            /node_modules/.test(file) &&
            !/\.vue\.js/.test(file)
        ),
        use: [
            'babel-loader'
        ]
      },
    ]
  }
}

loader

处理样式

因为webpack只能处理commonjs规范的js文件,所以处理别的文件的时候,需要用别的loader

npm install vue-style-loader style-loader css-loader postcss-loader sass sass-loader autoprefixer -D

html

npm install html-loader -D

创建HTML文件

npm install html-webpack-plugin -D

清除打包文件

npm i clean-webpack-plugin -D

处理图片等文件

不需要安装 file-loader 和 url-loader, webpack5内置好了

url-loader: 当文件大小达到一定要求的时候,可以将其处理成 base64 的 URIS ,内置 file-loader

webpack5: 提供了内置的静态资源构建能力,所以 url-loader 也不需要安装了

// webpack5 内置了loader
module.exports = {
    module: {
        rules: [
            {
                test: /\.(jpe?g|png|gif|svg)$/i,
                type: 'asset',
                generator: {
                    // [ext]前面自带"."
                    filename: 'assets/[name].[hash:7][ext]'
                }
            }
        ]
    }
}

环境变量

以 cross-env 的方式来设置环境变量, 因为他可以跨终端进行设置

npm install cross-env -D

// command
cross-env NODE_ENV=development

yargs

获取命令行参数

npm i yargs@13 -D

获取环境变量

命令加参数 --mode=development ps: 这里注意yargs的版本问题,如果使用下面的方式,建议用yargs@13 const argv = require('yargs').argv; 获取参数

chokidar

这个暂时不需要

chokidar 可以用于监控文件、文件夹变化

npm i chokidar --save-dev

打包压缩

提取CSS文件 & 压缩CSS

npm install mini-css-extract-plugin css-minimizer-webpack-plugin -D

mini-css-extract-plugin github 地址

压缩CSS

注意,用不同的

webpack5 压缩CSS 使用 css-minimizer-webpack-plugin ---- css-minimizer-webpack-plugin

webpack4 压缩CSS 使用 optimize-css-assets-webpack-plugin ---- optimize-css-assets-webpack-plugin

// 提取CSS文件
new MiniCssExtractPlugin({
    // filename: path.resolve(__dirname, 'dist/css/index.css')
    filename: 'css/[name].[contenthash:7].css'
})
// 压缩CSS
new OptimizeCssAssetsWebpackPlugin()

压缩JS

npm install terser-webpack-plugin -D

const TerserPlugin = require('terser-webpack-plugin');

optimization: {
    minimize: true,
    minimizer: [
        new TerserPlugin()
    ]
},

ESlint & stylelint

stylelint-webpack-plugin

typescript

npm install typescript ts-loader -D

加入VUE@3.x

npm install vue@next -S
npm install vue-loader@next @vue/compiler-sfc -D

postcss-loader

github.com/webpack-con…

功能:

  1. 把CSS解析为一个AST抽象语法树
  2. 调用插件,处理抽象语法树,并且添加功能

webpack-manifest-plugin

github.com/shellscape/…

const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
const options = { ... };

module.exports = {
  plugins: [
    new WebpackManifestPlugin(options)
  ]
};

optimization

// 告知 webpack 当选择模块 id 时需要使用哪种算法
optimization: {
    moduleIds: 'deterministic' // 被哈希转化成的小位数值模块名。
},

环境支持

Node V10.13.0 以上版本

参考资料

juejin.cn/post/692418…

github.com/zxpsuper/cr…

中文官网