When developing a component library or plug-in, it is often necessary to distinguish multiple environment builds to achieve:
- Provide various volume versions: full version, lite version, basic version, etc.;
- Provide various environment versions: web version, nodejs version, etc.;
- Various spec versions are available: esm spec version, cjs spec version, UMD spec version, etc.
So how can we easily realize the above functions? This scenario is suitable for using Feature Flags. During the construction process, the process of building code is dynamically set by enabling and disabling the switch, so as to better realize Tree Shaking.
Tree Shaking is a way to optimize volume by eliminating unused code in the final file.
This article will start with the construction process of Feature Flags used in the Vue source code (version number: 3.0.11), then learn through simple examples, and finally introduce the implementation in rollup, webpack and Vite.
The code address of this article: https://github.com/pingan8787/Leo-JavaScript/blob/master/Cute-Vue/Source/FeatureFlags/
1. What are Feature Flags
Feature Flag (also known as Feature Toggle, Flip, etc.) is a way to allow control of online features on or off, usually by means of configuration files.
It can be understood as adding a switch to the code. When the switch is turned on, the logic will be executed, otherwise it will not be executed. Usually the code expression is if
statement, for a simple example:
const flags = true;
const test = () => flags && console.log('Hello Feature Flags');
When flags
is true
, the output will be executed, otherwise it will not.
Now we want to control whether the log will be output or not, just change the value of flags
, and the method logic of test
does not need to be modified.
😺 Feature Flag can be translated into feature flag.
2. Vue3 source code implements Feature Flags
2.1 Example of use
After the introduction of the feature flag in the previous section, you should have a little understanding of it. Next, let's look at an example of use from the Vue3 source code:
// packages/compiler-core/src/errors.ts
export function defaultOnWarn(msg: CompilerError) {
__DEV__ && console.warn(`[Vue warn] ${msg.message}`)
}
The __DEV__
here is a Feature Flag. When the value of __DEV__
is true
, the following log will be output, otherwise it will not be output.
There are many other feature flags in the Vue3 source code, such as:
__COMMIT__
__TEST__
__GLOBAL__
- ...
There are many more, and interested friends can find them in the Vue3 source code.
2.2 How to define feature flags
The above is just to show you how to use it in the source code, then let's see how the feature flags of __DEV__
are defined.
Vue3 uses the @rollup/replace dependency. When building, replace the target string content in the file. For example, when building the package of the development environment, replace __DEV__
with true
.
Or take the example code above as an example:
// 本地开发环境 __DEV__ 为 true,经过 @rollup/replace 依赖打包后如下:
export function defaultOnWarn(msg: CompilerError) {
true && console.warn(`[Vue warn] ${msg.message}`)
}
// 生成环境中 __DEV__ 为 false,经过 @rollup/replace 依赖打包后如下:
export function defaultOnWarn(msg: CompilerError) {
}
After the build, the console.warn
statement in the defaultOnWarn
method was removed by Tree Shaking.
3. Get started with Feature Flags
In this section, we will use rollup, webpack and Vite to implement the demos of three Feature Flags respectively. The core principle is that during the construction phase, the content of the specified Feature Flags value will be replaced with a specific value, and then Tree Shaking will be performed.
The full code of the three examples can be viewed in the following repository:
First, let's create a index.js
file and enter the following test content:
// index.js
const name = 'pingan8787';
const age = 18;
const featureFlags = () => {
console.warn(name)
__DEV__ && console.log(name)
}
featureFlags();
The goal we need to achieve is: when the value of the __DEV__
variable is true
, the packaged index.js
will not contain the line of code __DEV__ && console.log(name)
.
So start to see how to implement:
3.1 rollup implementation
In rollup, you need to use the @rollup/replace package to replace text at build time, let's install it first:
npm install @rollup/plugin-replace --save-dev
Then in rollup.config.js
use:
import replace from '@rollup/plugin-replace';
export default {
input: 'index.js',
output: {
file: './dist/index.js',
format: 'cjs'
},
plugins: [
replace({
__DEV__: true
})
]
};
Next, through the rollup
packaging command, you can see the output as follows:
const name = 'pingan8787';
const age = 18;
const featureFlags = () => {
console.warn(name)
__DEV__ && console.log(name)
}
featureFlags();
It can be seen that when __DEV__
is true
, the code does not have Tree Shaking, and then try changing it to false
. The output is as follows:
'use strict';
const name = 'pingan8787';
const featureFlags = () => {
console.warn(name);
};
featureFlags();
Here __DEV__ && console.log(name)
has been removed to implement Tree Shaking.
Following the same principle, look at the implementation of webpack and Vite:
3.2 webpack implementation
Webpack comes with DefinePlugin
to implement this function. For details, please refer to the DefinePlugin document . Let’s take a look at webpack.config.js
configuration:
// webpack.config.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
entry: './index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js',
},
mode: 'production',
plugins: [
new webpack.DefinePlugin({
__DEV__: JSON.stringify(true),
})
],
};
Because this is using mode: 'production'
mode, the packaged code will be compressed:
(()=>{const n="pingan8787";console.warn(n),console.log(n)})();
It can be seen that __DEV__
no longer exists, but console.log(n)
still exists. At this time, change __DEV__
to false
and look at the packaging result:
console.warn("pingan8787");
Only this sentence is left, and the others have been dropped by Tree Shaking.
3.3 Vite Implementation
Vite also supports custom global variables by default, to achieve this function, you can see the document define option .
Create a simple Vite project with pnpm create vite
, delete the redundant content, and add our test code in main.js
:
import { createApp } from 'vue'
import App from './App.vue'
const name = 'pingan8787';
const age = 18;
const featureFlags = () => {
console.warn(name)
__DEV__ && console.log(name)
}
featureFlags();
createApp(App).mount('#app')
and set vite.config.js
in __DEV__
:
// vite.config.js
export default defineConfig({
plugins: [vue()],
define: {
__DEV__: true
}
})
Then execute pnpm build
to build the project, you can see that __DEV__ && console.log(name)
still exists in the compressed code.
Next, modify the value of __DEV__
to false
, and then repackage it. You can see that the code has been Tree Shaking:
3.4 Attention
If the editor prompts that the __DEV__
variable does not exist, you can create a new type declaration file to solve it, for example, create a new global.d.ts
file to define the content as follows:
// Global compile-time constants
declare var __DEV__: boolean
So far, we have implemented Feature Flags using rollup, webpack and Vite respectively.
4. Summary
This article introduces the concept and simple implementation of Feature Flags through simple examples and Vue3 source code, and finally implements Feature Flags using rollup, webpack and Vite respectively.
In actual business development, we can design various Feature Flags to make the code better for Tree Shaking.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。