likes
comments
collection
share

一篇教你学会如何用Webpack从零搭建一个Vue脚手架

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

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第20天,点击查看活动详情

前言

前面已经学习了一些webpack的基本配置,并从0搭建了一个React脚手架,接下来用学过的一些配置来搭建一个Vue脚手架!

开发模式下webpack配置

/*
 * @Author: fdhou
 * @Date: 2022-12-06 14:50:19
 * @LastEditors: fdhou
 * @LastEditTime: 2022-12-09 14:16:02
 * @Description: 开发环境webpack配置
 */
const path = require('path')
const { DefinePlugin } = require('webpack')
const ESLintWebpackPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { VueLoaderPlugin } = require('vue-loader')

// 获取处理样式的Loaders
const getStyleLoaders = (preProcessor) => {
  return [
    "vue-style-loader", // 需要处理css功能和HMR功能
    "css-loader",
    {
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: [
            "postcss-preset-env", // 能解决大多数样式兼容性问题
          ],
        },
      },
    },
    preProcessor,
  ].filter(Boolean);
};
module.exports = {
  entry: './src/main.js',
  output: {
    path: undefined, //开发环境不需要指定输出目录
    filename: 'static/js/[name].js', // 输出的文件名
    chunkFilename: 'static/js/[name].chunk.js', // 动态导入的文件打包输出的文件名
    assetModuleFilename: 'static/media/[name][hash:10][ext][query]', // 图片等公共资源打包后的名字
  },
  module: {
    rules: [
      /**
       * 样式资源处理
       */
      {
        test: /\.css$/,
        use: getStyleLoaders()
      },
      {
        test: /\.less$/,
        use: getStyleLoaders("less-loader"),
      },
      {
        test: /\.s[ac]ss$/,
        use: getStyleLoaders("sass-loader"),
      },
      {
        test: /\.styl$/,
        use: getStyleLoaders("stylus-loader"),
      },
      /**
       * 图片资源处理
       */
      {
        test: /\.(png|jpe?g|gif|svg)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
          },
        },
      },
      /**
       * 字体图标处理
       */
      {
        test: /\.(ttf|woff2?)$/,
        type: "asset/resource", // 原封不动输出
      },
      /**
       * js资源处理
       */
      {
        test: /\.js$/,
        include: path.resolve(__dirname, "../src"),
        loader: 'babel-loader',
        options: {
          cacheDirectory: true, // 开启babel编译缓存
          cacheCompression: false, // 缓存文件不要压缩
        }
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      }
    ]
  },
  plugins: [
    new ESLintWebpackPlugin({
      context: path.resolve(__dirname, "../src"),// 要处理的文件范围
      exclude: "node_modules",
      cache: true,
      cacheLocation: path.resolve(__dirname, "../node_modules/.cache/.eslintcache"), // 缓存目录
    }),
    // 处理html资源
    new HtmlWebpackPlugin({
      // 以 public/index.html 为模板创建文件
      // 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
      template: path.resolve(__dirname, "../public/index.html"),
    }),
    new VueLoaderPlugin(),
    // cross-env定义的环境变量给打包工具webpack使用
    // DefinePlugin定义的环境变量给代码内部使用!
    new DefinePlugin({
      __VUE_OPTIONS_API__: true,
      __VUE_PROD_DEVTOOLS__: false
    })
  ],
  optimization: {
    splitChunks: {
      chunks: "all", // 代码分割
    },
    runtimeChunk: {
      name: (entrypoint) => `runtime~${entrypoint.name}`,
    },
  },
  mode: "development",
  devtool: "cheap-module-source-map",
  // webpack解析模块加载选项
  resolve: {
    // 自动补全扩展名
    extensions: [".vue", ".js", ".json"]
  },
  // 自动化配置
  devServer: {
    open: true, // 是否自动打开浏览器
    host: "localhost",
    port: 4000,
    hot: true, // 热模块替换
    historyApiFallback: true, // 解决react-router刷新404问题
  },
}

遇到的问题

环境变量

在完成基础的配置页面打开之后,控制台会报如下警告,说环境变量没有被定义,所以我们需要定义这两个环境变量! 一篇教你学会如何用Webpack从零搭建一个Vue脚手架

解决

因为cross-env是给webpack使用的,但是这两个环境变量是在vue内部使用,所以我们需要用到webpack内置的一个插件DefinePlugin(专门用来定义环境变量给代码内部使用!),配置如下,配置完成之后就不会出现警告了!

webpack.dev.js

const { DefinePlugin } = require('webpack')
plugins:[
    // cross-env定义的环境变量给打包工具webpack使用
    // DefinePlugin定义的环境变量给代码内部使用!
    new DefinePlugin({
        __VUE_OPTIONS_API__: true,
        __VUE_PROD_DEVTOOLS__: false
    })
]

The template rootrequires exactly one element

在Vue3中<template>支持多个根节点,但是发现代码依然在标红,虽然是能够正常运行的。找到原因是因为安装了插件vetur,但是vetur只能够去验证vue2的代码规范,就会导致标红报错!只需要将插件禁用即可,vue3 推荐使用Volar来替换vetur 一篇教你学会如何用Webpack从零搭建一个Vue脚手架

生产环境webpack配置

生产环境和开发环境配置基本是一样的,只需要做如下配置:

  • 将css提取成单独文件用MiniCssExtractPlugin.loader
  • 对图片进行一下压缩用image-minimizer-webpack-plugin
  • 将public目录下的文件在打包时复制到dist目录下面用copy-webpack-plugin
  • 代码可以看github地址

生产模式和开发模式配置合并

github地址,Vue脚手架也有开发模式和生产模式合并的配置,主要就是通过下面这段代码去判断环境变量,判断当前运行的环境,去执行相对应的loader等,就不放代码了,可以在github看到。

// 获取cross-env定义的环境变量
const isProduction = process.env.NODE_ENV === 'production'

配置优化

element-plus按需引入

参考文档element-plus官方文档, 首先你需要安装unplugin-vue-components 和 unplugin-auto-import这两款插件,然后进行如下配置即可完成按需引入!

npm install -D unplugin-vue-components unplugin-auto-import
// webpack.config.js
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')

module.exports = {
  plugins: [
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],
}

自定义主题颜色

参考element-plus官方文档,更改自定义主题是通过 SCSS 变量来进行改的,只需要进行如下配置,进行引入即可。

// styles/element/index.scss
/* 只需要重写你需要的即可 */
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
  $colors: (
    'primary': (
      'base': green,
    ),
  ),
);

// 如果只是按需导入,则可以忽略以下内容。
// 如果你想导入所有样式:
// @use "element-plus/theme-chalk/src/index.scss" as *;

手动引入

// main.js
......
import './styles/element/index.scss'

自动引入

使用 scss.additionalData 来编译所有应用 scss 变量的组件。

//webpack/config.js
// 获取处理样式的Loaders
const getStyleLoaders = (preProcessor) => {
  return [
    isProduction ? MiniCssExtractPlugin.loader : 'vue-style-loader',
    "css-loader",
    {
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: [
            "postcss-preset-env", // 能解决大多数样式兼容性问题
          ],
        },
      },
    },
    preProcessor && {
      loader: preProcessor,
      options: preProcessor === 'sass-loader' ? {
        additionalData: `@use "@/styles/element/index.scss" as *;`, // 自动引入
      } : {}
    }
  ].filter(Boolean);
};
......
plugins:[
  Components({
    resolvers: [
      ElementPlusResolver({
        // 自定义主题引入sass
        importStyle: 'sass'
      })
    ],
  }),
]

tips

additionalData: `@use "~/styles/element/index.scss" as *;`,

在官网中是这样写,~是路劲别名,通常我们使用@,需要进行配置才可以生效:

// webpack.config.js
......
// webpack解析模块加载选项
resolve: {
  // 自动补全扩展名
  extensions: [".vue", ".js", ".json"],
  alias: {
    "@": path.resolve(__dirname, '../src')
  }
}
......

这样配置就完成了,按钮就从原来的蓝色变成了绿色! 一篇教你学会如何用Webpack从零搭建一个Vue脚手架

代码分割优化

因为node-moudel中的文件打包成单独一个文件的话太大,会影响加载速度也会影响按需引入的使用!所以我们可以将其进行分割进行单独打包,配置如下:

// webpack.config.js
optimization:{
    splitChunks: {
      chunks: "all", // 代码分割
      cacheGroups: {
        vue: {
          test: /[\\/]node_modules[\\/]vue(.*)[\\/]/,
          name: 'vue-chunk',
          priority: 40
        },
        elementPlus: {
          test: /[\\/]node_modules[\\/]element-plus[\\/]/,
          name: 'elementPlus-chunk',
          priority: 30
        },
        libs: {
          test: /[\\/]node_modules[\\/]/,
          name: 'libs-chunk',
          priority: 20
        }
      }
    }
}

关闭性能分析提升打包速度

// webpack.config.js
  .....
  performance: false

其他配置

// package.json
{
  "name": "Vue-scaffold",
  "version": "1.0.0",
  "description": "",
  "main": ".eslintrc.js",
  "scripts": {
    "start": "npm run dev",
    "dev": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.config.js",
    "build": "cross-env NODE_ENV=production webpack --config ./config/webpack.config.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/eslint-parser": "^7.19.1",
    "@vue/cli-plugin-babel": "^5.0.8",
    "@vue/compiler-sfc": "^3.2.45",
    "babel-loader": "^9.1.0",
    "copy-webpack-plugin": "^11.0.0",
    "cross-env": "^7.0.3",
    "css-loader": "^6.7.2",
    "css-minimizer-webpack-plugin": "^4.2.2",
    "eslint": "^8.29.0",
    "eslint-plugin-vue": "^9.8.0",
    "eslint-webpack-plugin": "^3.2.0",
    "html-webpack-plugin": "^5.5.0",
    "image-minimizer-webpack-plugin": "^3.8.1",
    "imagemin": "^8.0.1",
    "less-loader": "^11.1.0",
    "mini-css-extract-plugin": "^2.7.2",
    "postcss-loader": "^7.0.2",
    "postcss-preset-env": "^7.8.3",
    "sass": "^1.56.2",
    "sass-loader": "^13.2.0",
    "stylus-loader": "^7.1.0",
    "unplugin-auto-import": "^0.12.0",
    "unplugin-vue-components": "^0.22.11",
    "vue-loader": "^17.0.1",
    "vue-style-loader": "^4.1.3",
    "vue-template-compiler": "^2.7.14",
    "webpack": "^5.75.0",
    "webpack-cli": "^5.0.1",
    "webpack-dev-server": "^4.11.1"
  },
  "dependencies": {
    "element-plus": "^2.2.26",
    "vue": "^3.2.36",
    "vue-router": "^4.1.6"
  }
}
// babel.config.js
module.exports = {
  // 用来编译ES6的语法
  presets: ["@vue/cli-plugin-babel/preset"],
}
// eslinttr.js
module.exports = {
  root: true,
  env: {
    node: true,
  },
  extends: ["plugin:vue/vue3-essential", "eslint:recommended"],
  parserOptions: {
    parser: "@babel/eslint-parser",
  },
};

小结

通过以上配置,就完成了使用webpack从0搭建一个vue脚手架,且进行了一些优化配置。今天是更文的第20天了,距离4级只需要280掘力值了,加油!

转载自:https://juejin.cn/post/7175386566993870903
评论
请登录