Browse Source

feat: 全局注入变量

chenlei 2 years ago
parent
commit
008fc3a3ba
13 changed files with 2349 additions and 53 deletions
  1. 7 6
      .eslintrc.js
  2. 4 0
      .husky/commit-msg
  3. 4 0
      .husky/pre-commit
  4. 7 0
      .prettierignore
  5. 9 0
      .prettierrc
  6. 7 1
      README.md
  7. 2 1
      babel.config.js
  8. 3 0
      commitlint.config.js
  9. 35 1
      config.js
  10. 22 5
      package.json
  11. 2152 28
      pnpm-lock.yaml
  12. 11 0
      src/views/home/index.hn.tsx
  13. 86 11
      vue.config.js

+ 7 - 6
.eslintrc.js

@@ -4,16 +4,17 @@ module.exports = {
     node: true,
   },
   extends: [
-    "plugin:vue/vue3-essential",
-    "eslint:recommended",
-    "@vue/typescript/recommended",
-    "plugin:prettier/recommended",
+    'plugin:vue/vue3-essential',
+    'eslint:recommended',
+    '@vue/typescript/recommended',
+    'plugin:prettier/recommended',
   ],
   parserOptions: {
     ecmaVersion: 2020,
   },
   rules: {
-    "no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
-    "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
+    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
+    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
+    'vue/multi-word-component-names': 'off',
   },
 };

+ 4 - 0
.husky/commit-msg

@@ -0,0 +1,4 @@
+#!/bin/sh
+. "$(dirname "$0")/_/husky.sh"
+
+pnpm commitlint --edit $1

+ 4 - 0
.husky/pre-commit

@@ -0,0 +1,4 @@
+#!/bin/sh
+. "$(dirname "$0")/_/husky.sh"
+
+npx lint-staged

+ 7 - 0
.prettierignore

@@ -0,0 +1,7 @@
+build/
+**/*.png
+**/*.svg
+**/*.jpg
+.DS_Store
+.history
+package.json

+ 9 - 0
.prettierrc

@@ -0,0 +1,9 @@
+{
+  "$schema": "http://json.schemastore.org/prettierrc",
+  "singleQuote": true,
+  "semi": true,
+  "trailingComma": "es5",
+  "printWidth": 100,
+  "proseWrap": "never",
+  "vueIndentScriptAndStyle": true
+}

+ 7 - 1
README.md

@@ -1,5 +1,11 @@
+## 初始化
+
+``` bash
+pnpm install
+```
+
 ## 多场景模式
 
-通过 `process.env.MUSEUM` 区分博物馆
+通过 `process.env.SCENE` 区分场景
 
 尽量使用 `.tsx` 后缀,因为 `.vue` 为自定义后缀,webpack暂不能友好支持 `.vue` 后缀,需要明确使用 `demo.vue`,导致无法区分场景

+ 2 - 1
babel.config.js

@@ -1,3 +1,4 @@
 module.exports = {
-  presets: ["@vue/cli-plugin-babel/preset"],
+  plugins: ['lodash'],
+  presets: ['@vue/cli-plugin-babel/preset'],
 };

+ 3 - 0
commitlint.config.js

@@ -0,0 +1,3 @@
+module.exports = {
+  extends: ['@commitlint/config-conventional'],
+};

+ 35 - 1
config.js

@@ -1,5 +1,27 @@
+const pkg = require('./package.json');
+
 const ASSETS_DIR = 'resources/web/';
 
+/**
+ * 主域名
+ */
+const DOMAIN = '192.168.20.11';
+
+/**
+ * 前端版本号
+ */
+const VERSION = pkg.version;
+
+/**
+ * HTTP 协议
+ */
+const PROTOCOL = 'https';
+
+/**
+ * API 域名
+ */
+const BACKEND_DOMAIN = process.env.DOMAIN || `www.${DOMAIN}`;
+
 module.exports = {
   /**
    * 静态资源部署位置
@@ -9,4 +31,16 @@ module.exports = {
    * 静态资源放置的子目录
    */
   assetsDir: ASSETS_DIR,
-}
+  /**
+   * 可访问的内置常量
+   */
+  constants: {
+    ASSETS_DIR,
+    VERSION,
+    PROTOCOL,
+    DOMAIN,
+    BACKEND_DOMAIN,
+    ASSETS_URL: `/${ASSETS_DIR}`,
+    BACKEND_URL: `${PROTOCOL}://${BACKEND_DOMAIN}`,
+  },
+};

+ 22 - 5
package.json

@@ -3,17 +3,21 @@
   "version": "0.1.0",
   "private": true,
   "scripts": {
-    "serve:hn": "cross-env MUSEUM=hn vue-cli-service serve",
-    "build:hn": "cross-env MUSEUM=hn vue-cli-service build",
-    "lint": "vue-cli-service lint"
+    "serve:hn": "cross-env SCENE=hn vue-cli-service serve",
+    "build:hn": "cross-env SCENE=hn vue-cli-service build",
+    "lint": "vue-cli-service lint",
+    "prepare": "husky install"
   },
   "dependencies": {
     "core-js": "^3.8.3",
+    "lodash": "^4.17.21",
     "vue": "^3.2.13",
     "vue-class-component": "^8.0.0-0",
     "vue-router": "^4.0.3"
   },
   "devDependencies": {
+    "@commitlint/config-conventional": "^17.6.5",
+    "@types/lodash": "^4.14.195",
     "@typescript-eslint/eslint-plugin": "^5.4.0",
     "@typescript-eslint/parser": "^5.4.0",
     "@vue/cli-plugin-babel": "~5.0.0",
@@ -22,18 +26,31 @@
     "@vue/cli-plugin-typescript": "~5.0.0",
     "@vue/cli-service": "~5.0.0",
     "@vue/eslint-config-typescript": "^9.1.0",
+    "babel-plugin-lodash": "^3.3.4",
+    "commitlint": "^17.6.5",
     "cross-env": "^7.0.3",
     "eslint": "^7.32.0",
     "eslint-config-prettier": "^8.3.0",
     "eslint-plugin-prettier": "^4.0.0",
     "eslint-plugin-vue": "^8.0.3",
+    "husky": "^8.0.3",
+    "json-loader": "^0.5.7",
     "lint-staged": "^11.1.2",
+    "lodash-webpack-plugin": "^0.11.6",
+    "node-polyfill-webpack-plugin": "^2.0.1",
     "prettier": "^2.4.1",
     "sass": "^1.32.7",
     "sass-loader": "^12.0.0",
+    "svg-sprite-loader": "^6.0.11",
     "typescript": "~4.5.5"
   },
-  "gitHooks": {
-    "pre-commit": "lint-staged"
+  "lint-staged": {
+    "*.{js,jsx,ts,tsx,vue}": [
+      "eslint --fix",
+      "prettier --write"
+    ],
+    "*.{scss,less,styl,html}": [
+      "prettier --write"
+    ]
   }
 }

File diff suppressed because it is too large
+ 2152 - 28
pnpm-lock.yaml


+ 11 - 0
src/views/home/index.hn.tsx

@@ -0,0 +1,11 @@
+import { defineComponent } from 'vue';
+
+export default defineComponent({
+  name: 'Home',
+  setup() {
+    console.log(process.env.SCENE);
+  },
+  render() {
+    return <div>hn home</div>;
+  },
+});

+ 86 - 11
vue.config.js

@@ -1,38 +1,113 @@
-const { defineConfig } = require("@vue/cli-service");
+const { defineConfig } = require('@vue/cli-service');
+const webpack = require('webpack');
 const path = require('path');
 const config = require('./config');
+const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
+const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
 
 const IS_PRODUCTION = process.env.NODE_ENV === 'production';
-// 当前博物馆
-const MUSEUM = process.env.MUSEUM;
+// 当前场景
+const SCENE = process.env.SCENE;
 
-if (MUSEUM != null) {
-  console.log('当前博物馆:', MUSEUM);
+if (SCENE != null) {
+  console.log('当前场景:', SCENE);
 }
 
+const ENV = getEnv();
+
 module.exports = defineConfig({
   transpileDependencies: true,
   lintOnSave: false,
   publicPath: IS_PRODUCTION ? config.publicPath : '/',
-  outputDir: (IS_PRODUCTION && !!MUSEUM) ? `build/${MUSEUM}` : 'build',
-  // 根据博物馆隔离
-  assetsDir: path.posix.join(config.assetsDir, MUSEUM || ''),
+  outputDir: IS_PRODUCTION && !!SCENE ? `build/${SCENE}` : 'build',
+  // 根据场景隔离
+  assetsDir: path.posix.join(config.assetsDir, SCENE || ''),
 
   configureWebpack: {
+    devtool: 'source-map',
     resolve: {
       symlinks: false,
       alias: {
         '@': path.join(__dirname, 'src'),
       },
     },
+    plugins: [
+      new NodePolyfillPlugin(),
+
+      // 扩展 process.env
+      new webpack.DefinePlugin(ENV.define),
+    ],
   },
 
   chainWebpack: (webpackConfig) => {
-    if (MUSEUM != null) {
+    if (SCENE != null) {
       const extensions = webpackConfig.resolve.extensions.values();
       for (let i = extensions.length - 1; i >= 0; i--) {
-        webpackConfig.resolve.extensions.prepend(`.${MUSEUM}${extensions[i]}`);
+        webpackConfig.resolve.extensions.prepend(`.${SCENE}${extensions[i]}`);
       }
     }
-  }
+
+    webpackConfig.module
+      .rule('json')
+      .test(/(.*)\.tr$/)
+      .use('json-loader')
+      .loader('json-loader')
+      .end();
+
+    webpackConfig.module.rules.delete('svg'); // 删除默认svg配置
+    webpackConfig.module
+      .rule('svg-sprite-loader')
+      .test(/\.svg$/)
+      .use('svg-sprite-loader')
+      .loader('svg-sprite-loader')
+      .options({
+        symbolId: 'icon-[name]',
+      })
+      .end();
+
+    if (IS_PRODUCTION) {
+      webpackConfig.plugin('loadshReplace').use(new LodashModuleReplacementPlugin());
+    }
+  },
 });
+
+/**
+ * 初始化环境变量
+ */
+function getEnv() {
+  const constants = config.constants;
+
+  // 扩展内置变量
+  for (const key in constants) {
+    process.env[`VUE_APP_${key}`] = constants[key];
+  }
+
+  // 内置变量
+  const vueVariables = ['NODE_ENV', 'BASE_URL'];
+  const variableNames = [...vueVariables, 'SCENE'];
+  const variables = [];
+
+  for (const key in process.env) {
+    if (key.startsWith('VUE_APP_')) {
+      variableNames.push(key);
+    }
+  }
+
+  variableNames.forEach((name) => {
+    variables.push(`${name}: "${process.env[name]}"`);
+  });
+
+  return {
+    variableNames,
+    variables,
+    // 用于 definePlugin
+    define: variableNames
+      .filter((name) => {
+        return !name.startsWith('VUE_APP_') && !vueVariables.includes(name);
+      })
+      .reduce((prev, cur) => {
+        prev[`process.env.${cur}`] = JSON.stringify(process.env[cur]);
+        return prev;
+      }, {}),
+  };
+}