Personally, I think Vben Admin is a good project, complete and well-documented, and the technology stack is always up to date. When I was following through with the documentation, I didn’t immediately use it because I didn’t understand a lot of things.

Of course, it is also necessary to use it after all understanding it. After all, it is much better to use it and watch it. The guide part of the document on how to use it is very clear and the source code is highly encapsulated, and this part is often the need to modify according to the actual business, so I decided to take a look at this part of the source code before using.

  • Vben Admin in-depth understanding of routing, menu, permission design

Doubt point

This section focuses on the handling of environment variables and how to use a Vite plug-in.

In Vite only variables starting with VITE_ are embedded in client-side packages. A new variable whose rule starts with VITE_GLOB_ will be added to _app.config.js when packing.

  • So what transformations and extensions have been done to the environment variables?
  • then_app.config.jsHow is it generated and written?

Parse the environment variable file

Start with the viet.config. ts entry.

Use loadEnv to read the corresponding environment configuration file (.env +.env.[mode] +.env.[mode].local), which can be used in the subsequent configuration. Load mode details environment variables and modes.

// vite.config.ts
import { loadEnv } from 'vite';
import { wrapperEnv } from './build/utils';
export default ({ command, mode }: ConfigEnv): UserConfig= > {
  const root = process.cwd();

  // Load environment variables for the corresponding schema
  const env = loadEnv(mode, root);

  // Parse the values of environment variables
  const viteEnv = wrapperEnv(env);
  };
};
Copy the code

Use wrapperEnv to further process the read content.

// build/utils.ts
export function wrapperEnv(envConf: Recordable) :ViteEnv {
  const ret: any = {};

  for (const envName of Object.keys(envConf)) {
    let realName = envConf[envName].replace(/\\n/g."\n");

    // Convert Boolean values
    realName = realName === "true" ? true : realName === "false" ? false : realName;

    // Convert port configuration
    if (envName === "VITE_PORT") {
      realName = Number(realName);
    }

    // Transform proxy configuration
    if (envName === "VITE_PROXY") {
      try {
        realName = JSON.parse(realName);
      } catch (error) {}
    }

    ret[envName] = realName;

    // Why do I assign to process.env? What's the use of that?
    if (typeof realName === "string") {
      process.env[envName] = realName;
    } else if (typeof realName === "object") {
      process.env[envName] = JSON.stringify(realName); }}return ret;
}
Copy the code

Then pass the parsed viteEnv into the plug-in list for use.

// vite.config.ts
export default ({ command, mode }: ConfigEnv): UserConfig= > {
  const viteEnv = wrapperEnv(env);
  return {
    plugins: createVitePlugins(viteEnv, isBuild)
  };
};
Copy the code

How is _app.config.js generated

After the search logic, a script is executed using ESno to generate the build.

"build": "cross-env NODE_ENV=production vite build && esno ./build/script/postBuild.ts"
Copy the code

The main function is to parse the environment variable file and write the contents to the file.

// build/script/buildConf.ts
function createConfig({ configName, config, configFileName = GLOB_CONFIG_FILE_NAME }) {
  try {
    // File contents
    const windowConf = `window.${configName}`;
    const configStr = `${windowConf}=The ${JSON.stringify(config)};
      Object.freeze(${windowConf});
      Object.defineProperty(window, "${configName}", {
        configurable: false,
        writable: false,
      });
    `.replace(/\s/g."");
    fs.mkdirp(getRootPath(OUTPUT_DIR));
    // Generate the file
    writeFileSync(getRootPath(`${OUTPUT_DIR}/${configFileName}`), configStr);
  } catch (error) {
    console.log(chalk.red("configuration file configuration file failed to package:\n"+ error)); }}export function runBuildConfig() {
  // Get the values starting with VITE_GLOB_ in the environment variable configuration file, which are resolved by Dotenv like Vite
  const config = getEnvConfig();
  // Get the variable configuration name '__PRODUCTION__${env.vite_glob_app_short_name}__CONF__'
  const configFileName = getConfigFileName(config);
  // Generate code and write to file
  createConfig({ config, configName: configFileName });
}
Copy the code

Finally, _app.config.js is introduced in index. HTML, where the use of viet-plugin-html is also written by the Vben authors themselves.

Plugins are centrally managed in build/vite/plugin, and after configuration are processed, the array is returned and configured to vite plugins.

// build/vite/plugin/html.ts
export function configHtmlPlugin(env: ViteEnv, isBuild: boolean) {
  const { VITE_GLOB_APP_TITLE, VITE_PUBLIC_PATH } = env;

  const path = VITE_PUBLIC_PATH.endsWith("/")? VITE_PUBLIC_PATH :`${VITE_PUBLIC_PATH}/ `;

  // Get the path configuration
  const getAppConfigSrc = () = > {
    return `${path || "/"}${GLOB_CONFIG_FILE_NAME}? v=${pkg.version}-The ${new Date().getTime()}`;
  };

  const htmlPlugin: Plugin[] = html({
    minify: isBuild,
    inject: {
      data: {
        title: VITE_GLOB_APP_TITLE
      },
      // Build mode imports the app.config.js file
      tags: isBuild ? [{tag: "script".attrs: {
                src: getAppConfigSrc()
              }
            }
          ]
        : []
    }
  });
  return htmlPlugin;
}
Copy the code

Use of environment variables

First of all, we can still use the method provided by Vite.

import.meta.env.VITE_XXX;
Copy the code

According to the documentation, useGlobSetting is used to obtain the dynamic configuration.

// src/hooks/setting/index.ts
export const useGlobSetting = () = > {
  const { VITE_GLOB_APP_TITLE } = getAppEnvConfig(); // The production environment is dynamically configured
  const glob = {
    title: VITE_GLOB_APP_TITLE
  };
  return glob;
};
Copy the code

Implementation of dynamic configuration in production environment.

// src/utils/env.ts
export function getAppEnvConfig() {
  // Get the alias of the configuration
  const ENV_NAME = getConfigFileName(import.meta.env);

  // In the case of development, the development environment is retrieved from the environment variable
  // If the production environment gets (_app.config.js) from the window property
  const ENV = import.meta.env.DEV ? import.meta.env : window[ENV_NAME];

  const { VITE_GLOB_APP_TITLE } = ENV;

  return {
    VITE_GLOB_APP_TITLE
  };
}
Copy the code

conclusion

We know what and how Vben Admin does when we configure an environment variable. This way we can do whatever we want if we have problems or add new plugin logic.