unplugin-preprocessor-directives
v1.2.0
Published
<img src="assets/logo.svg" alt="logo" width="100" height="100" align="right" />
Maintainers
Readme
unplugin-preprocessor-directives
English | 简体中文
安装
npm i unplugin-preprocessor-directives[!IMPORTANT] 此插件应该放在配置中所有其他插件之前,以确保预处理器指令首先被处理。
// vite.config.ts
import PreprocessorDirectives from 'unplugin-preprocessor-directives/vite'
export default defineConfig({
plugins: [
PreprocessorDirectives({ /* options */ }), // 应该是第一个插件
],
})Example: playground/
// rollup.config.js
import PreprocessorDirectives from 'unplugin-preprocessor-directives/rollup'
export default {
plugins: [
PreprocessorDirectives({ /* options */ }),
],
}// webpack.config.js
module.exports = {
/* ... */
plugins: [
require('unplugin-preprocessor-directives/webpack')({ /* options */ })
]
}// nuxt.config.js
export default defineNuxtConfig({
modules: [
['unplugin-preprocessor-directives/nuxt', { /* options */ }],
],
})This module works for both Nuxt 2 and Nuxt Vite
// vue.config.js
module.exports = {
configureWebpack: {
plugins: [
require('unplugin-preprocessor-directives/webpack')({ /* options */ }),
],
},
}// esbuild.config.js
import { build } from 'esbuild'
import PreprocessorDirectives from 'unplugin-preprocessor-directives/esbuild'
build({
plugins: [PreprocessorDirectives()],
})// rspack.config.js
module.exports = {
plugins: [
require('unplugin-preprocessor-directives/rspack')({ /* options */ }),
],
}使用
定义 symbols
您可以使用以下两个预处理器指令来定义或取消定义 symbols,以便进行条件编译:
#define: 定义一个 symbol.#undef: 取消定义一个 symbol.
使用 #define 可以定义一个 symbol。将 symbol 作为表达式传递给 #if 指令时,表达式的值将为 true,如下例所示:
// #define VERBOSE
// #if VERBOSE
console.log('Verbose output version')
// #endif条件编译
#if: 打开条件编译,只有当指定的 symbol 被定义并求值为 true 时,代码才会被编译。#elif:关闭前面的条件编译,并判断是否定义了指定的 symbol 并求值为 true 时,打开一个新的条件编译。#else: 如果前一个指定的 symbol 未定义或求值为 false,则关闭前一个条件编译,并打开一个新的条件编译。#endif: 关闭前面的条件编译。
[!NOTE] 默认情况下,使用 vite 的
loadEnv函数根据process.env.NODE_ENV加载环境变量并作为条件编译 symbols。
// src/index.ts
// #if DEV
console.log('Debug version')
// #endif
// #if !MYTEST
console.log('MYTEST is not defined or false')
// #endif可以使用运算符 == (相等)和 != (不等)来测试 true 或 false。true 表示 symbol 已定义。语句 #if DEBUG 与 #if (DEBUG == true) 意义相同。支持使用 && (与)、|| (或) 和 ! (非) 操作符来判断是否定义了多个 symbols。还可以用括号将 symbols 和运算符分组。
class MyClass {
constructor() {
// #if (DEBUG && MYTEST)
console.log('DEBUG and MYTEST are defined')
// #elif (DEBUG==false && !MYTEST)
console.log('DEBUG and MYTEST are not defined')
// #endif
}
}错误、警告和信息提示
可以指示编译器生成用户定义的编译器错误、警告和信息。
#error: 生成一条错误消息,但不会终止编译。#warning: 生成一条警告消息。#info: 生成一条信息消息。
// #error this is an error message
// #warning this is a warning message
// #info this is an info message当然,也可以和条件编译结合使用:
// #if DEBUG
// #info Debug mode is on
// #endif
// #if !DEBUG
// #info Debug mode is off
// #endif#include 指令
您可以使用 #include 指令将其他文件的内容包含到当前文件中。被包含的文件也会经过预处理器处理。
[!WARNING]
#include指令是一个编译时文本替换工具,主要用于以下场景:
- 在不同环境下包含不同的配置代码片段
- 与条件编译结合使用,根据编译条件包含不同的代码
- 共享需要预处理的代码片段
它不能也不应该替代:
- JavaScript/TypeScript 的
import或require- 用于模块化和依赖管理- CSS 的
@import- 用于样式表的模块化- HTML 的模板系统或组件系统
如果您只是想要模块化代码,请使用语言原生的模块系统。只有在需要编译时处理和条件包含时才使用
#include。
该指令支持以下两种语法:
// #include "path/to/file"
or
// #include <path/to/file>[!NOTE]
- 循环引用: 如果文件 A 包含文件 B,而文件 B 又包含文件 A,会自动检测并阻止循环引用,只处理一次
- 路径解析: 相对路径是相对于配置的工作目录(
cwd)解析的- 文件扩展名: 可以包含任何类型的文本文件,不限于
.js文件- 嵌套处理: 包含的文件会完整地通过预处理器,所以可以使用所有支持的指令
自定义指令
您可以使用 defineDirective 定义自己的指令。
以内置指令为例:
export const MessageDirective = defineDirective<MessageToken, MessageStatement>(context => ({
lex(comment) {
return simpleMatchToken(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 })
break
case 'warning':
context.logger.warn(node.value, { timestamp: true })
break
case 'info':
context.logger.info(node.value, { timestamp: true })
break
}
return createProgramNode()
}
},
generate(node, comment) {
if (node.type === 'MessageStatement' && comment)
return `${comment.start} #${node.kind} ${node.value} ${comment.end}`
},
}))enforce: 'pre' | 'post'
指令的执行优先级
pre尽可能早执行post尽可能晚执行
