likes
comments
collection
share

webpack5搭建vue3教程

作者站长头像
站长
· 阅读数 13

vue-cli 5.0的webpack版本是5,本教程一些惯例尽量和vue-cli保持一致,求同存异. 你需要了解一些基本的webpack知识,比如loader,plugins,resolve

1. 初始化

新建一个目录,在该目录下执行命令

npm init

会提示你一些选项,除了入口文件默认是index.js,我们这里和vue-cli保持一直输入main.js,剩下的直接回车就好. 会在目录下生成一个package.json文件

webpack5搭建vue3教程

webpack5搭建vue3教程

2.搭建webpack环境

npm i webpack webpack-merge webpack-dev-serve webpack-cli -D

webpack是必装的,这个就不用介绍了 webpack-merge 这个是用来合并webpack配置文件的,比如一般项目有三个webpack配置文件,一个基础的 打包图片 样式啥的,一个生产环境的,一个开发环境的.开发环境就需要把基础配置文件合并进来再export webpack-dev-serve 提供一个本地serve服务器,webpack5自带了一个serve但是传言日志不好,暂时还是dev serve webpack-cli webpack-cli 可以让你在命令行中调用webpack

3.创建目录和文件

webpack5搭建vue3教程

创建红框里的目录和文件,其中index.html为了一致性直接用的vue-cli的index.html.把对ico文件的link那一行删掉

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

当然,你也可以自己定义一个更简单的,比如这样

<!DOCTYPE html>
<html lang="">
  <body>
    <div id="app"></div>
  </body>
</html>

4.基本配置

我们先做一个最简单的配置,看看webpack能不能跑起来

webpack.common.js配置

const path = require('path')

module.exports = env =>{
    return {
        entry:'./src/main.js',//入口文件
        stats: 'errors-only',//仅错误时显示logo
        output:{
            filename: 'assets/js/[name].code.js',
            chunkFilename: 'assets/js/[name].bundle.js',//动态导入 分离bundle 比如lodashjs配合注释import(/* webpackChunkName: "lodash" */ 'lodash') 会打包成lodash.bundle.js
            path: path.resolve(__dirname, '../dist'),
        }
    }
}

webpack.prod.js配置

//const webpack = require('webpack');
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = env =>{
    let pro_config = {
        mode:'production',
        // devtool:'source-map',//开启将会生成map文件
    }

    return merge(common(env),pro_config)  //合并配置
}

main.js

console.log('this is mainjs')

package.json

  "scripts": {
    "build": "webpack  --config build/webpack.prod.js"
  },

都是很基础的配置哈,大概说下逻辑. 当我们在命令行输入npm run build的时候,会执行webpack.prod.js文件, 在prod配置文件里,借助merge插件,会把webpack.common.js里的配置也执行起来. 在common文件里,入口是main.js,打包出口是dist目录 这时候我们执行run build 应该会看到新增加了一个目录,如图所示

webpack5搭建vue3教程

5.根据业务需求配置插件

我们的目标是搭建一个类似vue-cli的脚手架,所以我们需要如下插件

vue-loader

loader 用于对模块的源代码进行转换,vue-loader当然就是对vue代码进行转换,让浏览器能够识别. vue-loader除了在rules里配置外,还要在plugins配置下,是为了把其他定义的规则应用到vue文件里.

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

webpack.common.js文件:

const path = require('path')
const { VueLoaderPlugin } = require('vue-loader')

module.exports = env =>{
    return {
        entry:'./src/main.js',//入口文件
        output:{
            filename: 'assets/js/[name].code.js',
            chunkFilename: 'assets/js/[name].bundle.js',//动态导入 分离bundle 比如lodashjs配合注释import(/* webpackChunkName: "lodash" */ 'lodash') 会打包成lodash.bundle.js
            path: path.resolve(__dirname, '../dist'),
        },
        plugins:[
            new VueLoaderPlugin()
        ],
        module:{
            rules:[
                {
                    test:/\.vue$/,
                    loader:'vue-loader'
                },
                // 它会应用到普通的 `.js` 文件以及 `.vue` 文件中的 `<script>` 块
            ]
        }
    }
}

HtmlWebpackPlugin

HtmlWebpackPlugin可以让打包后的JS自动引入html文件中

npm i -D html-webpack-plugin

这个插件也属于生产和开发环境都用到的,所以在webpack.common.js文件里配置

const path = require('path')
const { VueLoaderPlugin } = require('vue-loader')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = env =>{
    return {
        entry:'./src/main.js',//入口文件
        output:{
            filename: 'assets/js/[name].code.js',
            chunkFilename: 'assets/js/[name].bundle.js',//动态导入 分离bundle 比如lodashjs配合注释import(/* webpackChunkName: "lodash" */ 'lodash') 会打包成lodash.bundle.js
            path: path.resolve(__dirname, '../dist'),
        },
        plugins:[
            new VueLoaderPlugin(),
            new HtmlWebpackPlugin({
                template: path.join(__dirname, '../public/index.html'),
                filename: 'index.html',//输出的文件名
            }),
        ],
        module:{
            rules:[
                {
                    test:/\.vue$/,
                    loader:'vue-loader'
                },
                // 它会应用到普通的 `.js` 文件以及 `.vue` 文件中的 `<script>` 块
            ]
        }
    }
}

bable-loader

这个就不多介绍了,能让你现在就用ES6 7 8的语法,官方教程

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

在webpack.common.js的rules里添加一条

module: {
      rules: [
        {
          test: /\.vue$/,
          loader: "vue-loader",
        }, // 它会应用到普通的 `.js` 文件以及 `.vue` 文件中的 `<script>`
        {
          test: /\.m?js$/,
          exclude: /(node_modules|bower_components)/,
          use: {
            loader: "babel-loader",
            options: {
              presets: ["@babel/preset-env"],
            },
          },
        },
      ],
    },

resolve

resolve主要是配置如会解析模块.常用的有两个extensions和alias,一个配置后缀名,可以不带后缀.一个配置引入别名,不用逐层引入 在webpack.common.js文件里配置

resolve:{  //配置模块如会解析
       extensions:['.vue','.js','.json'],//引入这些文件 可以不带后缀 按顺序解析
       alias:{
           '@':join('../src'), //@方式引入资源
       }
    },

webpack5搭建vue3教程

资源模块

资源模块比如png svg jpg等图片或者txt等,webpack5之前都是用file-loader或者url-loader来处理. webpack5现在会自动处理,不用再手动配置.小于8kb的资源视为inline资源处理,否则视为resource处理. 比如如果我们想规定小于6kb的图片才内联inline处理,否则就resource 引入. webpack.common.js里

 {
            test: /\.(png|svg|jpg|gif)$/,
            type: 'asset',
            parser: {
               dataUrlCondition: {
                   maxSize: 6 * 1024,//小于6kb的图片内联处理
               }
            }
        } 

5.开发环境配置

上面主要是webpack.common.js基础配置,下面我们根据开发环境定制需要的配置.

friendly-errors-webpack-plugin

执行npm run serve成功之后,可以在控制台输出信息

const { merge } = require("webpack-merge");
const common = require("./webpack.common.js");
const FriendlyErrorsPlugin = require("friendly-errors-webpack-plugin");
const ip = require("ip");

let port = "8082";

module.exports = (env) => {
  let dev_config = {
    devtool: 'inline-source-map',//开启source map
    mode: "development",
    plugins: [
      //运行成功,输出信息
      new FriendlyErrorsPlugin({
        compilationSuccessInfo: {
          messages: [
            `You application is running here http://${ip.address()}:${port} \r\nYou can also open local address http://localhost:${port}`,
          ],
          clearConsole: true,
        },
      }),
    ],
  };

  return merge(common(env), dev_config);
};

devserve

在devserve里我们可以指定端口号,是否支持https,是否打开浏览器窗口等. webpack5的devserve和webpack4的devserve变化挺大, 如果有devserve定制需求,建议去官网看下,不能盲目粘贴过来 在plugins下面增加一个同级的配置即可.

 devServer: {
      host: "0.0.0.0",
      port: port,
      open:"http://localhost:" + port,//打开指定窗口
      proxy: {
        "/api": {
          target: "http://www.xxx.com:8080/api",
          secure: true, // 如果是https接口,需要配置这个参数
          changeOrigin: true,
          pathRewrite: { "^/finchinaAPP": "" },
        },
      },
    },

cache

cache缓存生成的webpack模块和chunk,主要用来提升构建速度. 只在开发模式能用,默认是memory既缓存到内存中. 如果想自定义缓存策略,需要把cache的type值由memory改成filesystem. 比如修改默认缓存目录

const path = require('path');

module.exports = {
  //...
  cache: {
    type: 'filesystem',
    cacheDirectory: path.resolve(__dirname, '.temp_cache'),
  },
};

css处理

因为生产环境的CSS需要压缩,这里还是分别配置好了. 先安装style-loader 把CSS插入到DOM中.

npm install --save-dev style-loader

再安装css-loader 对 @import 和 url() 进行处理,就像 js 解析 import/require() 一样.

npm install --save-dev css-loader

最后在module的rules里增加一条规则

{
          //解析器的执行顺序是从下往上(先css-loader再style-loader)
          test: /\.css$/i,
          use: [
            "style-loader",
            {
              loader: "css-loader",
              options: {
                esModule: false,
                modules: {
                  auto: false, //modules 开关,移动端多页面模式关闭class hash命名
                  localIdentName: "[local]_[hash:base64:8]", // 自定义生成的类名
                },
              },
            },
          ],
        },

sass-css处理

一般项目都会用到css处理器,所以光处理css是不够的,假如项目用的是sass-css,这么解决. 安装node-sass sass-loader

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

在rulues里新增一个规则

 {
        test: /.s[ac]ss$/i,
        use: [
          // 将 JS 字符串生成为 style 节点
          'style-loader',
          // 将 CSS 转化成 CommonJS 模块
          'css-loader',
          // 将 Sass 编译成 CSS
          'sass-loader',
        ],
      },

less-css处理

如果用的是less-css 需要安装一个less-loader

npm install less less-loader --save-dev

然后在rules里配置下,这里没有按照less-loader的官网教程配置,因为报引入错误,可能文档没更新.

 {
          test: /\.less$/i,
          use: [
            // compiles Less to CSS
            "style-loader",
            "css-loader",
            "less-loader",
          ],
        },

到此,我们的开发环境就配置完了.

6.生产环境配置

webpack5相对于4自动化增强了,比如会自动清除输出目录下的历史文件,自动压缩JS等. css-loader sass-loader less-loader上面已经介绍过了就不多介绍了.

提取css

借助MiniCssExtractPlugin插件

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

然后在plugins和css loader配置

plugins: [        
            new webpack.DefinePlugin({
                'process.env.NODE_ENV': JSON.stringify('production')
            }),

            //提取CSS
            new MiniCssExtractPlugin({
                filename:`assets/css/[name].style.css`,
                chunkFilename:`assets/css/[name].css`
            }),
        ],
        module: {
            rules: [
                {
                    //解析器的执行顺序是从下往上(先css-loader再style-loader)
                    test: /\.css$/,
                    use: [
                        MiniCssExtractPlugin.loader,
                        {
                            loader: 'css-loader',
                            options: {
                                esModule: false,
                                modules:{
                                    auto:false,//modules 开关,移动端多页面模式关闭class hash命名
                                    localIdentName: '[local]_[hash:base64:8]',// 自定义生成的类名
                                }
                            }
                        },
                    ]
                },
                {
                    test: /\.scss$/,
                    use: [
                        MiniCssExtractPlugin.loader,
                        'css-loader',
                        'sass-loader'
                    ]
                },
                {
                    test: /\.less$/,
                    use: [
                        MiniCssExtractPlugin.loader,                    
                        'css-loader',
                        'less-loader'
                    ]
                },
            ]
        },

压缩css

webpack4使用的是OptimizeCSSAssetsPlugin,到了webpack5官方推荐使用CssMinimizerWebpackPlugin

 npm install css-minimizer-webpack-plugin --save-dev

然后在module同级新增一个配置

optimization: {
    minimizer: [
      // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
      // `...`,
      new CssMinimizerPlugin(),
    ],
  }

其实我们生产环境可以直接配置minimize: true,也行.

代码分离Optimization

Optimization,webpack5默认的构建目标是web. 如果是别的比如node项目或者electorn项目,需要增加一个target属性 比如构建node环境

module.exports = {
  target: 'node',
};

对于webpack的optimization,一般关注optimization.splitChunks多一些, splitChunks默认给我们配置了一套拆分规则

-   新的 chunk 可以被共享,或者模块来自于 `node_modules` 文件夹
-   新的 chunk 体积大于 20kb(在进行 min+gz 之前的体积)
-   当按需加载 chunks 时,并行请求的最大数量小于或等于 30
-   当加载初始化页面时,并发请求的最大数量小于或等于 30

optimization: {
    splitChunks: {
      chunks: 'async',
      minSize: 20000,
      minRemainingSize: 0,
      minChunks: 1,
      maxAsyncRequests: 30,
      maxInitialRequests: 30,
      enforceSizeThreshold: 50000,
      cacheGroups: {
        defaultVendors: {
          test: /[\/]node_modules[\/]/,
          priority: -10,
          reuseExistingChunk: true,
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
  },
}

我们也可以根据实际项目情况,做些调整,比如默认20kb开始分割代码,改成30KB分割代码等

splitChunks: {
                minChunks: 2,  //模块至少使用次数
                cacheGroups: {
                    vendor: {
                        name: 'vendor',
                        test: /[\\/]node_modules[\\/]/,
                        chunks: 'all',
                        priority: 2,  //2>0  nodulesmodules里的模块将优先打包进vendor
                    },
                    commons: {
                        name: "commons",   //async异步代码分割 initial同步代码分割 all同步异步分割都开启
                        chunks: "all",
                        minSize: 30000,         //字节 引入的文件大于30kb才进行分割    
                        priority: 0,   //优先级,先打包到哪个组里面,值越大,优先级越高
                    }
                }
            }

我们一般说优化项目,除了开源插件按需引入比如echarts,antdvue等,主要的是通过调整optimization的不同配置来优化打包效果.想深入研究webpack优化,建议多看看这个.

打包体积分析

打包后的代码,有时候文件比较大,需要分析下情况,这时候需要安装分析插件webpack-bundle-analyzer

npm install --save-dev webpack-bundle-analyzer

然后配置只有监听到输入分析命令后才启动,不然每次打包都要启动

webpack5搭建vue3教程

然后在package.json配置启动命令

"scripts": {
    "serve": "webpack-dev-server  --hot   --config build/webpack.dev.js",
    "dev": "webpack-dev-server --open --progress --config build/webpack.dev.js",
    "build": "webpack  --config  build/webpack.prod.js",
    "distanalyzer": "webpack --env.analyzer=true --config build/webpack.prod.js"
  },

至此,大功搞定.

7.跑起来试一下

安装vue-router

npm install vue-router@4

简单写两个页面,成功!

webpack5搭建vue3教程

具体代码已经放到GitHub上,点击这里.