Appearance
Vue 脚手架
目录结构
text
react_cli
├─ node_modules
├─ config
│ ├─ webpack.config.common.js #公共配置
│ ├─ webpack.dev.js #开发配置
│ └─ webpack.prod.js #生产配置
├─ public
│ ├─ favicon.ico
│ └─ index.html
├─ src
│ ├─ views
│ ├─ router
│ │ └─ index.js
│ ├─ main.js
│ └─ App.vue
├─ .eslintrc.js
├─ babel.config.js
└─ package.json
公共配置
js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const EslintWebpackPlugin = require("eslint-webpack-plugin");
const { VueLoaderPlugin } = require("vue-loader");
const { DefinePlugin } = require("webpack");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const isProduction = process.env.NODE_ENV === "production";
// 样式处理函数
const getStyleLoader = () => {
return [
isProduction ? MiniCssExtractPlugin.loader : "vue-style-loader",
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: ["postcss-preset-env"], //处理绝大多数样式兼容问题
},
},
},
];
};
module.exports = {
entry: "./src/main.js",
// 解析器
module: {
rules: [
{
oneOf: [
{ test: /\.css$/, use: [...getStyleLoader()] },
{
test: /\.less$/,
use: [...getStyleLoader(), "less-loader"],
},
{
test: /\.s[ac]ss$/,
use: [...getStyleLoader(), "sass-loader"],
},
{
test: /\.(jpe?g|png|gif|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, //小于10kb的图片将会被转化为base64格式
},
},
},
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",
},
{
test: /\.js$/,
include: path.resolve(__dirname, "../src"),
loader: "babel-loader",
options: {
cacheDirectory: true, //开启缓存
cacheCompression: false, //关闭缓存压缩
},
},
],
},
//vue-loader 不支持oneOf
{
test: /\.vue$/,
loader: "vue-loader", //该插件内部会给vue文件注入HMR功能
options: {
//开启缓存
cacheDirectory: path.resolve(__dirname, "node_modules/.cache/vue-loader"),
},
},
],
},
// 插件
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"),
favicon: path.resolve(__dirname, "../public/favicon.ico"),
}),
new EslintWebpackPlugin({
context: path.resolve(__dirname, "../src"),
exclude: "node_modules",
cache: true,
cacheLocation: path.resolve(__dirname, "../node_modules/.cache/.eslintcache"),
}),
// 处理vue文件
new VueLoaderPlugin(),
// 解决页面警告
new DefinePlugin({
__VUE_OPTIONS_API__: "true",
__VUE_PROD_DEVTOOLS__: "false",
}),
],
// 优化
optimization: {
splitChunks: {
chunks: "all",
cacheGroups: {
elementUI: {
name: "chunk-elementPlus",
test: /[\\/]node_modules[\\/]_?element-plus(.*)/,
priority: 30,
},
vue: {
name: "vue",
test: /[\\/]node_modules[\\/]vue(.*)[\\/]/,
chunks: "initial",
priority: 20,
},
libs: {
name: "chunk-libs",
test: /[\\/]node_modules[\\/]/,
priority: 10, // 权重最低,优先考虑前面内容
chunks: "initial",
},
},
},
},
resolve: {
extensions: [".js", ".json", ".vue"],
alias: {
"@": path.resolve(__dirname, "../src"),
},
},
};
开发配置
js
const { merge } = require("webpack-merge");
const commonConfig = require("./webpack.common");
const devConfig = {
output: {
path: undefined,
filename: "static/js/[name].js",
chunkFilename: "static/js/[name].chunk.js",
},
devServer: {
host: "localhost",
port: "3000",
open: false,
historyApiFallback: true, // 解决router刷新404问题
},
mode: "development",
devtool: "cheap-module-source-map",
};
// 合并公共配置
module.exports = merge(commonConfig, devConfig);
生产配置
js
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const TerserWebpackPlugin = require("terser-webpack-plugin");
const { merge } = require("webpack-merge");
const CommonConfig = require("./webpack.common");
const prodConfig = {
output: {
path: path.resolve(__dirname, "../dist"),
filename: "static/js/[name].[chunkhash:8].js",
chunkFilename: "static/js/[name].[chunkhash:8].chunk.js",
clean: true,
},
// 插件
plugins: [
// 抽离css
new MiniCssExtractPlugin({
filename: "static/css/[name].[contenthash:8].css",
chunkFilename: "static/css[name].[contenthash:8].chunk.css",
}),
],
// 优化
optimization: {
minimizer: [
new CssMinimizerPlugin(), //压缩css
//压缩js
new TerserWebpackPlugin({
extractComments: false, //不将注释提取到单独文件
}),
],
},
mode: "production",
devtool: "source-map",
performance: false, // 关闭性能分析,提示速度
};
module.exports = merge(CommonConfig, prodConfig);
其他配置
package.json
json
{
"name": "vue-cli",
"version": "1.0.0",
"description": "",
"main": ".eslintrc.js",
"scripts": {
"start": "npm run dev",
"dev": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.dev.js",
"build": "cross-env NODE_ENV=production webpack --config ./config/webpack.prod.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.20.5",
"@babel/eslint-parser": "^7.19.1",
"@vue/cli-plugin-babel": "^5.0.8",
"babel-loader": "^9.1.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",
"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.1",
"sass-loader": "^13.2.0",
"style-loader": "^3.3.1",
"vue-loader": "^17.0.1",
"vue-style-loader": "^4.1.3",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.0",
"webpack-dev-server": "^4.11.1",
"webpack-merge": "^5.8.0"
},
"dependencies": {
"element-plus": "^2.2.26",
"vue": "^3.2.45",
"vue-router": "^4.1.6"
},
"browserslist": ["> 1%", "not dead", "last 2 versions"]
}
.eslintrc.js
js
module.exports = {
root: true,
env: {
node: true,
},
extends: ["plugin:vue/vue3-essential", "eslint:recommended"],
parserOptions: {
parser: "@babel/eslint-parser", //解析babel
},
};
babel.config.js
js
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"],
};
vue 相关配置
App.vue
vue
<template>
<div>
<h1 class="title">hello app</h1>
<el-button type="primary" @click="toggleDark()">按钮</el-button>
<ul>
<li>
<router-link to="/home">home</router-link>
</li>
<li>
<router-link to="/about">about</router-link>
</li>
</ul>
<router-view></router-view>
</div>
</template>
<script setup>
import { useDark, useToggle } from "@vueuse/core";
import { reactive, toRefs, onBeforeMount, onMounted } from "vue";
const isDark = useDark();
const toggleDark = useToggle(isDark);
</script>
<style scoped lang="scss">
.title {
color: yellowgreen;
}
</style>
main.js
js
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import ElementPlus from "element-plus";
import "./styles/element/index.scss";
// import 'element-plus/dist/index.css'
const app = createApp(App);
app.use(router).use(ElementPlus).mount(document.getElementById("app"));
router
js
import { createRouter, createWebHistory } from "vue-router";
export const routes = [
{
path: "/home",
name: "Home",
component: () => import("@/views/home"),
},
{
path: "/about",
name: "About",
component: () => import("@/views/about"),
},
];
let router = createRouter({
history: createWebHistory(),
routes,
});
export default router;