English | 简体中文
npm i unplugin-preprocessor-directivesNote
This plugin should be placed before all other plugins in your configuration to ensure preprocessor directives are processed first.
Vite
// vite.config.tsimportPreprocessorDirectivesfrom'unplugin-preprocessor-directives/vite'exportdefaultdefineConfig({plugins: [PreprocessorDirectives({/* options */}),// Should be the first plugin],})Example: playground/
Rollup
// rollup.config.jsimportPreprocessorDirectivesfrom'unplugin-preprocessor-directives/rollup'exportdefault{plugins: [PreprocessorDirectives({/* options */}),],}Webpack
// webpack.config.jsmodule.exports={/* ... */plugins: [require('unplugin-preprocessor-directives/webpack')({/* options */})]}Nuxt
// nuxt.config.jsexportdefaultdefineNuxtConfig({modules: [['unplugin-preprocessor-directives/nuxt',{/* options */}],],})This module works for both Nuxt 2 and Nuxt Vite
Vue CLI
// vue.config.jsmodule.exports={configureWebpack: {plugins: [require('unplugin-preprocessor-directives/webpack')({/* options */}),],},}esbuild
// esbuild.config.jsimport{build}from'esbuild'importPreprocessorDirectivesfrom'unplugin-preprocessor-directives/esbuild'build({plugins: [PreprocessorDirectives()],})Rspack (⚠️ experimental)
// rspack.config.jsmodule.exports={plugins: [require('unplugin-preprocessor-directives/rspack')({/* options */}),],}You use the following two preprocessor directives to define or undefine symbols for conditional compilation:
#define: Define a symbol.#undef: Undefine a symbol.
You use #define to define a symbol. When you use the symbol as the expression that's passed to the #if directive, the expression will evaluate to true, as the following example shows:
// #define VERBOSE// #if VERBOSEconsole.log('Verbose output version')// #endif#if: Opens a conditional compilation, where code is compiled only if the specified symbol is defined and evaluated to true.#elif: Closes the preceding conditional compilation and opens a new conditional compilation based on if the specified symbol is defined and evaluated to true.#else: Closes the preceding conditional compilation and opens a new conditional compilation if the previous specified symbol isn't defined or evaluated to false.#endif: Closes the preceding conditional compilation.
Note
By default, use vite's loadEnv function to load environment variables based on process.env.NODE_ENV and compile symbols as conditions.
// src/index.ts// #if DEVconsole.log('Debug version')// #endif// #if !MYTESTconsole.log('MYTEST is not defined or false')// #endifYou can use the operators == (equality) and != (inequality) to test for the bool values true or false. true means the symbol is defined. The statement #if DEBUG has the same meaning as #if (DEBUG == true). You can use the && (and), || (or), and ! (not) operators to evaluate whether multiple symbols have been defined. You can also group symbols and operators with parentheses.
classMyClass{constructor(){// #if (DEBUG && MYTEST)console.log('DEBUG and MYTEST are defined')// #elif (DEBUG==false && !MYTEST)console.log('DEBUG and MYTEST are not defined')// #endif}}You instruct the compiler to generate user-defined compiler errors and warnings and informational messages.
#error: Generates an error, but does not terminate compilation.#warning: Generates a warning.#info: Generates an informational message.
// #error this is an error message// #warning this is a warning message// #info this is an info messageOf course, it can also be combined with conditional compilation:
// #if DEBUG// #info Debug mode is on// #endif// #if !DEBUG// #info Debug mode is off// #endifYou can use the #include directive to include the contents of other files into the current file. The included files are also processed by the preprocessor.
Warning
The #include directive is a compile-time text replacement tool, primarily intended for these scenarios:
- Including different configuration code snippets in different environments
- Combining with conditional compilation to include different code based on compilation conditions
- Sharing code snippets that require preprocessing
It cannot and should not replace:
- JavaScript/TypeScript
importorrequire- for modularization and dependency management - CSS
@import- for stylesheet modularization - HTML template systems or component systems
If you simply want to modularize your code, please use the language's native module system. Only use #include when you need compile-time processing and conditional inclusion.
this directive supports the following two syntaxes:
// #include "path/to/file"or// #include <path/to/file>Note
- Circular references: If file A includes file B, and file B includes file A, circular references will be automatically detected and prevented, processing only once
- Path resolution: Relative paths are resolved relative to the configured working directory (
cwd) - File extensions: Any type of text file can be included, not limited to
.jsfiles - Nested processing: Included files are fully processed by the preprocessor, so all supported directives can be used
You can used defineDirective to define your own directive.
Taking the built-in directive as an example:
exportconstMessageDirective=defineDirective<MessageToken,MessageStatement>(context=>({lex(comment){returnsimpleMatchToken(comment,/#(error|warning|info)\s*(.*)/)},parse(token){if(token.type==='error'||token.type==='warning'||token.type==='info'){this.current++return{type: 'MessageStatement',kind: token.type,value: token.value,}}},transform(node){if(node.type==='MessageStatement'){switch(node.kind){case'error':
context.logger.error(node.value,{timestamp: true})breakcase'warning':
context.logger.warn(node.value,{timestamp: true})breakcase'info':
context.logger.info(node.value,{timestamp: true})break}returncreateProgramNode()}},generate(node,comment){if(node.type==='MessageStatement'&&comment)return`${comment.start} #${node.kind}${node.value}${comment.end}`},}))Execution priority of directives
pre: Execute as early as possiblepost: Execute as late as possible