Introduction to the
Project: Use vue-CLI-service as the Vue project to start devServer and package build tools.
Requirement scenarios:
- Development: Start devServer of each environment, and you can call the back-end interface of different environment locally during the joint adjustment
- Build: Package the code of each environment. The back-end server address of each environment is different. After deployment, the front-end project of each environment will call the back-end interface of the corresponding environment (development, test, UAT, and production)
The above usage scenarios often occur in the development process. Based on this background, the following is a review of some records in the process of multi-environment configuration scheme of a VUE project based on vue-CLI-service source code (skip to the “scheme implementation” section at the end of viewing the specific scheme)
Mode
In the multi-environment configuration of a VUE project, the concept of Mode (environment Mode) in VUe-cli-service should be paid attention to. There are three modes in vue-cli-service:
-
Development: The default mode when vue-cli-service serve is executed.
-
Test: vue-cli-service test: default mode for unit execution. This mode will be injected after the @vue/test-utils plug-in is installed.
-
Production: the default mode when vue-cli-service build is executed. When the mode is not specified through the –mode command line flag, vue-cli-service will infer a default mode based on the different parameters at the time of executing the command.
Mode and the Environment
Several enumerated values Mode is easy to confuse with the concept of Environment (Environment), the Mode has a development/test/production, the Environment can have a lot of kinds, Common ones are development/test/UAT/production.
-
Mode
- Vue-cli-service performs different operations in different modes. For example, in development Mode, vue-cli-service is executed in development scenarios. Vue-cli-service automatically generates a webPack configuration optimized for development and enables devServer so that the project can be opened locally for debugging.
- The webpack configuration generated in development mode and Production mode will be different. Production mode will optimize the packaged code, for example, production mode will add code compression, subcontracting, file name adding hash value and other configurations.
-
Environment
- Different environments refer to the operating environments of the packaged code. The application scenarios are as follows: The back-end interface address may be different when the code in different environments invokes the back-end interface domain name. For example, the front-end project on the development server invokes the back-end interface domain name
https://dev.xxx.com/apis
, the domain name of the back-end interface invoked by the front-end project deployed on the test server ishttps://test.xxx.com/apis
When executing vue-cli-service build, set Mode to development instead of production. The deployed code may have problems with no code compression (large volume) and no hash value after the file name (each update requires the user to flush the cache to take effect).
- Different environments refer to the operating environments of the packaged code. The application scenarios are as follows: The back-end interface address may be different when the code in different environments invokes the back-end interface domain name. For example, the front-end project on the development server invokes the back-end interface domain name
What happens after vue-cli-service XXX is executed
This section covers only mode-related content, but not the rest.
PS: This section is best served with @vue/ CLI-service source code.
1, the entrance
The entry file of the vue-cli-service command is @/ vue-cli-service /bin/vue-cli-service.js, that is, the logic behind executing the vue-cli-service command is to execute this file. The minimist process for parameters passed in through vue-cli-service XXX is passed into the service.run method.
const rawArgv = process.argv.slice(2)
const args = require('minimist')(rawArgv, {
boolean: [
// build
'modern'.'report'.'report-json'.'inline-vue'.'watch'.// serve
'open'.'copy'.'https'.// inspect
'verbose']})// vue-cli-service XXX is the first parameter after the command. In normal cases, it is serve/build/test:unit
const command = args._[0]
service.run(command, args, rawArgv).catch(err= > {
error(err)
process.exit(1)})Copy the code
2. Determine the mode
# @vue/cli-service/lib/Service.js
class Service{
// modes are provided for @vue/cli-service/lib/commands/ files loaded by resolvePlugins during initialization. See constructor for details
modes={
"serve": "development"."test:unit": "test"."build": "production"
}
// name=serve|build|test:unit
run(name, args = {}, rawArgv = []) {
const mode = args.mode || (name === 'build' && args.watch ? 'development' : this.modes[name])
}
}
Copy the code
As shown above, the inference logic of mode (in order of priority) :
vue-cli-service serve --mode development
Through:--mode
Specifies the mode with the highest priorityvue-cli-service build --watch
: Run the mode command. The default value is development- Other scenarios are based on
modes[name]
Automatic matching
3. Initialize environment variables
Env.[mode]. Local and. Env.[mode] files in the root directory of the project are read and loaded by the dotenv library, assigning internal variables to process.env one by one.
4. Determine NODE_ENV
# @vue/cli-service/lib/Service.js Service.loadEnv()
const defaultNodeEnv = (mode === 'production' || mode === 'test')? mode :'development'
if (process.env.NODE_ENV == null) {
process.env.NODE_ENV = defaultNodeEnv
}
if (process.env.BABEL_ENV == null) {
process.env.BABEL_ENV = defaultNodeEnv
}
Copy the code
This is the logic that defines process.env.node_env and process.env.babel_env. The mode used in this section is the value obtained in the “Determine mode” section.
Process.env.node_env and process.env.babel_env. These two variables are used in subsequent vue-CLI-service generation of webpack configuration and use of Babel, which explains why the correct use of mode is so important. For example, only when process.env.node_env =production can the packaged code have the effect of code compression and file name hash. Do not specify NODE_ENV in an env file unless you specify it for a specific purpose, otherwise it will affect the definition of the default NODE_ENV value if you specify process.env.node_env by loading the env file in advance, as shown in the section “Initializing environment variables”.
Webpack config contrast
Vue-cli-service inspect –mode XXX can be used to obtain the webpack configuration information generated in development and production mode. Some differences are as follows:
Plan implementation
The new directory structure is as follows:
When the environment-related variable files are moved from the root directory to the cli/environments/ folder, the original logic of vue-cli-service reads the env file in the root directory based on mode. The env file in cli/environments/ stores environment-related variables, such as:
# cli/environments /. Env. Dev VUE_APP_ENV = dev # # is used to identify the current environment interface server address API_HOST = HTTPS://dev.xxx.com/apis
Copy the code
@vue/cli-service/bin/vue-cli-service.js /vue /cli-service/bin/vue-cli-service.js
# cli/index.js
const { semver, error } = require("@vue/cli-shared-utils");
const requiredVersion = require("@vue/cli-service/package.json").engines.node;
const dotenv = require("dotenv");
const dotenvExpand = require("dotenv-expand");
const path = require("path");
if (
!semver.satisfies(process.version, requiredVersion, {
includePrerelease: true,
})
) {
error(
`You are using Node ${process.version}, but vue-cli-service ` +
`requires Node ${requiredVersion}.\nPlease upgrade your Node version.`
);
process.exit(1);
}
const Service = require("@vue/cli-service/lib/Service");
const service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd());
const rawArgv = process.argv.slice(2);
const args = require("minimist")(rawArgv, {
boolean: [
// build
"modern"."report"."report-json"."inline-vue"."watch".// serve
"open"."copy"."https".// inspect
"verbose",]});const command = args._[0];
const env = args.env || "dev";
loadEnv(env);
service.run(command, args, rawArgv).catch((err) = > {
error(err);
process.exit(1);
});
/ * * *@description: load env file *@param {String} (dev env environment | test | uat | prod) * /
function loadEnv(env) {
try {
const envOptions = ["dev"."test"."uat"."prod"];
if(! envOptions.includes(env)) {throw new Error(
`env: ${env} is invalid, options: The ${JSON.stringify(envOptions)}`
);
}
const envPath = path.resolve(process.cwd(), `cli/environments/.env.${env}`);
const localPath = `${envPath}.local`;
// Load the.env.local file
const localEnvConfig = dotenv.config({
path: localPath,
debug: process.env.DEBUG,
});
dotenvExpand(localEnvConfig);
// Load the env file
const envConfig = dotenv.config({ path: envPath, debug: process.env.DEBUG });
dotenvExpand(envConfig);
} catch (err) {
// Ignore that there is no error in the file
if (err.toString().indexOf("ENOENT") < 0) {
error(err);
process.exit(1)}}}Copy the code
Finally modify scripts in package.json file:
# package.json
{
"scripts": {
"serve:dev": "node ./cli serve --env dev"."serve:test": "node ./cli serve --env test"."serve:uat": "node ./cli serve --env uat"."serve:prod": "node ./cli serve --env prod"."build:dev": "node ./cli build --env dev"."build:test": "node ./cli build --env test"."build:uat": "node ./cli build --env uat"."build:prod": "node ./cli build --env prod"}}Copy the code
conclusion
To sum up this plan, the main work is as follows:
- Distinguish betweenEnvironment variable fileandPattern variable file, the mode variable file is placed in the root directory of the project, vue-cli-service will automatically load. The environment variable file moves to
/cli/environments/
Directory, by/cli/index.js
The added logic in the. - new
/cli/index.js
The original logic of vue-cli-service is migrated to the file and added to the file/cli/environments/
Directory under the environment variable file logic, manual processing of the required environment variable file.
Any other ideas are welcome