基于webpack5搭建的vue2脚手架
- 本代码已发布npm,直接使用npm即可安装
- npm i webpack-vue2-cli -g
- wvc 项目名称
内容简介
1.ESLint插件
2.图片压缩
3.代码压缩
4.项目拆包分包
5.前端离线化
…
- 等等一系列优化操作以及详细的注释,方便同学们学习
- 当时写这套代码的原因是因为公司老项目各方面性能太慢,所以决定升级脚手架
- 也可用于公司老项目直接嵌套进来直接使用
为什么需要打包工具?
开发时,我们会使用框架(React、Vue),ES6 模块化语法,Less/Sass 等 css 预处理器等语法进行开发。
这样的代码要想在浏览器运行必须经过编译成浏览器能识别的 JS、Css 等语法,才能运行。
所以我们需要打包工具帮我们做完这些事。
除此之外,打包工具还能压缩代码、做兼容性处理、提升代码性能等。
文件组成目录
├── webpack-test (项目根目录)
├── webpack.dev.js(配置文件)
├── node_modules (下载包存放目录)
├── src (项目源码目录,除了html其他都在src里面)
│ └── 略
├── public (项目html文件)
│ └── index.html
├── .eslintrc.js(Eslint配置文件)
├── babel.config.js(Babel配置文件)
└── package.json (包的依赖管理配置文件)
webpack.config.js
const os = require("os");
const path = require("path");
// ESLint插件
// const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
// 图片压缩
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
//代码压缩
const TerserWebpackPlugin = require("terser-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
// VueLoader
const VueLoaderPlugin = require("vue-loader/lib/plugin-webpack5");
const { DefinePlugin } = require("webpack");
// 进度条插件
const WebpackBar = require('webpackbar');
// 离线化
// const WorkboxPlugin = require("workbox-webpack-plugin");
// // cpu核数
const threads = os.cpus().length;
// 需要通过 cross-env 定义环境变量
const isProduction = process.env.NODE_ENV === "production";
const getStyleLoaders = (preProcessor) => {
return [
isProduction ? MiniCssExtractPlugin.loader : "vue-style-loader",
"css-loader",
// Css 兼容性处理
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: ["postcss-preset-env"],// 能解决大多数样式兼容性问题
},
},
},
preProcessor && {
loader: preProcessor,
// options:
// preProcessor === "sass-loader"
// ? {
// // 自定义主题:自动引入我们定义的scss文件
// additionalData: `@use "@/styles/element/index.scss" as *;`,
// }
// : {},
},
].filter(Boolean);
};
module.exports = {
// 入口
entry: "./src/main.js",
// 出口
output: {
// 出口文件inde.html访问的路径
publicPath: '/',
path: isProduction ? path.resolve(__dirname, "dist") : undefined,
// 普通文件
filename: isProduction
? "js/[name].[contenthash:10].js"
: "js/[name].js",
// 异步加载的文件(比如点击执行的)
chunkFilename: isProduction
? "js/[name].[contenthash:10].chunk.js"
: "js/[name].chunk.js",
// 静态文件
assetModuleFilename: "assets/[hash:10][ext][query]",
clean: true,
// 默认 webpack 会在输出的 bundle 中生成路径信息,将路径信息删除可小幅提升构建速度。
pathinfo: false,
},
module: {
// lodaer存放地区
// 资源模块(asset module)是一种模块类型,它允许使用资源文件(字体,图标等)而无需配置额外 loader。
// asset/resource 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现。
// asset/inline 导出一个资源的 data URI。之前通过使用 url-loader 实现。
// asset/source 导出资源的源代码。之前通过使用 raw-loader 实现。
// asset 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源体积限制实现。
rules: [
{
test: /\.css$/,
// use 数组里面 Loader 执行顺序是从右到左
use: getStyleLoaders(),
},
{
test: /\.s[ac]ss$/,
use: getStyleLoaders("sass-loader"),
},
{
test: /\.(png|jpe?g|gif|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, //图片大于10*1024进行base64转码
},
},
generator: {
filename: 'assets/img/[hash][ext][query]' // 局部指定输出位置
}
},
{
test: /\.(ttf|woff2?|map4|map3|avi)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",
generator: {
filename: 'assets/font/[hash][ext][query]' // 局部指定输出位置
}
},
{
test: /\.js$/,
include: path.resolve(__dirname, "src"),//include查找src文件下内容,exclude用于排除某文件外
loader: "babel-loader",
options: {
cacheDirectory: true,// 开启babel编译缓存
cacheCompression: false,// 缓存文件不要压缩
plugins: [
// "@babel/plugin-transform-runtime" //减少代码体积, presets中包含了
],
},
// use: [
// {
// loader: "thread-loader", // 开启多进程
// options: {
// workers: threads, // 数量
// },
// },
// {
// loader: "babel-loader",
// options: {
// cacheDirectory: true, // 开启babel编译缓存
// cacheCompression: false,// 缓存文件不要压缩
// },
// },
// ],
},
// vue-loader不支持oneOf
{
test: /\.vue$/,
loader: "vue-loader", // 内部会给vue文件注入HMR功能代码
options: {
// 开启缓存
cacheDirectory: path.resolve(
__dirname,
"node_modules/.cache/vue-loader"
),
},
// 项目大的话可以尝试给这个loader开启单独线程运行提高效率
// use: [
// {
// loader: 'vue-loader',
// options: {
// // 开启缓存
// cacheDirectory: path.resolve(
// __dirname,
// "node_modules/.cache/vue-loader"
// ),
// },
// },
// {
// loader: 'thread-loader',
// },
// ],
},
],
},
// 插件存放地区
plugins: [
// new ESLintWebpackPlugin({
// 指定检查文件的根目录
// context: path.resolve(__dirname, "../src"),
// exclude: "node_modules",
// cache: true,
// cacheLocation: path.resolve(
// __dirname,
// "../node_modules/.cache/.eslintcache"
// ),
// }),
new WebpackBar({
// color: "#85d", // 默认green,进度条颜色支持HEX
// basic: true, // 默认true,启用一个简单的日志报告器
// profile: true, // 默认false,启用探查器。
}),
new HtmlWebpackPlugin({
// 以 public/index.html 为模板创建文件
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
template: path.resolve(__dirname, "public/index.html"),
}),
// 复制文件
new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, "public"),
to: path.resolve(__dirname, "dist"),
toType: "dir",
noErrorOnMissing: true,
globOptions: {
ignore: ["**/index.html"],
},
info: {
minimized: true,
},
},
],
}),
// 提取css成单独文件
isProduction &&
new MiniCssExtractPlugin({
// 定义输出文件名和目录
filename: "assets/css/[name].[contenthash:10].css",
chunkFilename: "assets/css/[name].[contenthash:10].chunk.css",
}),
new VueLoaderPlugin(),
new DefinePlugin({
__VUE_OPTIONS_API__: "true",
__VUE_PROD_DEVTOOLS__: "false",
'process.env': {
VUE_APP_HOST: isProduction // 将属性转化为全局变量,让代码中可以正常访问
}
}),
// // https和本地可以用
// new WorkboxPlugin.GenerateSW({
// // 这些选项帮助快速启用 ServiceWorkers
// // 不允许遗留任何“旧的” ServiceWorkers,更新代码自动替换资源刷新网页
// clientsClaim: true,
// skipWaiting: true,
// exclude: [/.*\.mp4$/], // 此处添加过滤规则
// maximumFileSizeToCacheInBytes: 10485760, // 适当调整预缓存的单个文件大小上限10mb以下的存储
// }),
].filter(Boolean),
// 代码处理
optimization: {
// 告知 webpack 使用 TerserPlugin 或其它在 optimization.minimizer定义的插件压缩 bundle
minimize: isProduction,
// 压缩的操作
minimizer: [
new CssMinimizerPlugin(),//压缩css
// 当生产模式会默认开启TerserPlugin,压缩 JavaScript,但是我们需要进行其他配置,就要重新写了
new TerserWebpackPlugin({//代码压缩
parallel: threads, // 开启多进程,填入数字是开启几个线程
terserOptions: {
compress: {
drop_console: true, //去除log
},
},
}),
// 压缩图片
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminGenerate,
options: {
plugins: [
["gifsicle", { interlaced: true }],
["jpegtran", { progressive: true }],
["optipng", { optimizationLevel: 5 }],
[
"svgo",
{
plugins: [
"preset-default",
"prefixIds",
{
name: "sortAttrs",
params: {
xmlnsOrder: "alphabetical",
},
},
],
},
],
],
},
},
}),
],
// 拆包区域
splitChunks: {
chunks: "all", //指定打包同步加载还是异步加载
cacheGroups: {
// layouts通常是admin项目的主体布局组件,所有路由组件都要使用的
// 可以单独打包,从而复用
// 如果项目中没有,请删除
// layouts: {
// name: "layouts",
// test: path.resolve(__dirname, "../src/layouts"),
// priority: 40,
// },
// 如果项目中使用element-plus,此时将所有node_modules打包在一起,那么打包输出文件会比较大。
// 所以我们将node_modules中比较大的模块单独打包,从而并行加载速度更好
// 如果项目中没有,请删除
elementUI: {
name: "chunk-element",
test: /[\\/]node_modules[\\/]_?element-ui(.*)/,
priority: 30,
},
// 将vue相关的库单独打包,减少node_modules的chunk体积。
vue: {
name: "vue",
test: /[\\/]node_modules[\\/]vue(.*)[\\/]/,
chunks: "initial",
priority: 20,
},
libs: {
name: "chunk-libs",
test: /[\\/]node_modules[\\/]/,
priority: 10, // 权重最低,优先考虑前面内容
chunks: "initial",
},
},
},
// 为运行时代码创建一个额外的 chunk,减少 entry chunk 体积,提高性能。
runtimeChunk: {
name: (entrypoint) => `runtime~${entrypoint.name}`,
},
},
// resolve 用来配置 webpack 如何解析模块,可通过优化 resolve 配置来覆盖默认配置项,减少解析范围
resolve: {
modules: ['node_modules'],// 指定查找依赖包目录
// 需要解析的文件类型列表。由于 webpack 的解析顺序是从左到右,因此要将使用频率高的文件类型放在左侧,如下我将 vue 放在最左侧。
extensions: [".vue", ".js", ".json"],
alias: {
// 路径别名
"@": path.resolve(__dirname, "src"),
},
fallback: { "stream": false } //vue-loader相关报错解决办法
},
// 开发服务器
devServer: {
open: true,
host: "localhost",
port: 3000,
hot: true, //热模块更新
compress: true,
historyApiFallback: true, // 解决vue-router刷新404问题
},
//Webpack默认在生产环境下(mode:'production')自动进行代码压缩,内部用的是terser-webpack-plugin插件
mode: isProduction ? "production" : "development",
//错误代码信息标注,第一个是行,第二个是行加列,关闭默认按最大性能处理,开启方便查错
// devtool: isProduction ? "source-map" : "cheap-module-source-map",
performance: false,
};
// Tree Shaking 也叫摇树优化,基于ESModules模块化(即只有ESModules的模块化代码才能使Tree Shaking生效),在production生产环境下默认开启
.eslintrc.js
Eslint
可组装的 JavaScript 和 JSX 检查工具。
这句话意思就是:它是用来检测 js 和 jsx 语法的工具,可以配置各项功能
我们使用 Eslint,关键是写 Eslint 配置文件,里面写上各种 rules 规则,将来运行 Eslint 时就会以写的规则对代码进行检查
module.exports = {
root: true,
env: {
node: true,
},
extends: ["plugin:vue/vueessential", "eslint:recommended"],// 继承 vue插件规则和 Eslint 规则
parserOptions: {
parser: "@babel/eslint-parser", 支持最新的最终 ECMAScript 标准
},
};
babel.config.js
Babel
JavaScript 编译器。
主要用于将 ES6 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"],// 使用vue预设
};
关于作者
开源项目,感觉不错的话辛苦给个star哦:https://gitee.com/chen-xinke/vue2-webpack-cli.git
有任何问题也欢迎随时交流