KeJunMao / unplugin-preprocessor-directives

preprocessor directives for jsx,tsx,js,ts,html,css,vue and more
MIT License
70 stars 7 forks source link
conditional-compilation directives esbuild preprocessor rollup unplugin vite webpack
logo

unplugin-preprocessor-directives

npm version npm downloads github stars bundle License JSDocs

English | 简体中文

[!IMPORTANT] If you like this project, please consider giving it a star ⭐️. Your support will help this project become a part of the unplugin organization!

Install

npm i unplugin-preprocessor-directives
Vite
```ts // vite.config.ts import PreprocessorDirectives from 'unplugin-preprocessor-directives/vite' export default defineConfig({ plugins: [ PreprocessorDirectives({ /* options */ }), ], }) ``` Example: [`playground/`](./playground/)
Rollup
```ts // rollup.config.js import PreprocessorDirectives from 'unplugin-preprocessor-directives/rollup' export default { plugins: [ PreprocessorDirectives({ /* options */ }), ], } ```
Webpack
```ts // webpack.config.js module.exports = { /* ... */ plugins: [ require('unplugin-preprocessor-directives/webpack')({ /* options */ }) ] } ```
Nuxt
```ts // nuxt.config.js export default defineNuxtConfig({ modules: [ ['unplugin-preprocessor-directives/nuxt', { /* options */ }], ], }) ``` > This module works for both Nuxt 2 and [Nuxt Vite](https://github.com/nuxt/vite)
Vue CLI
```ts // vue.config.js module.exports = { configureWebpack: { plugins: [ require('unplugin-preprocessor-directives/webpack')({ /* options */ }), ], }, } ```
esbuild
```ts // esbuild.config.js import { build } from 'esbuild' import PreprocessorDirectives from 'unplugin-preprocessor-directives/esbuild' build({ plugins: [PreprocessorDirectives()], }) ```
Rspack (⚠️ experimental)
```ts // rspack.config.js module.exports = { plugins: [ require('unplugin-preprocessor-directives/rspack')({ /* options */ }), ], } ```

Usage

Defining symbols

You use the following two preprocessor directives to define or undefine symbols for conditional compilation:

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 VERBOSE
console.log('Verbose output version')
// #endif

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 DEV
console.log('Debug version')
// #endif

// #if !MYTEST
console.log('MYTEST is not defined or false')
// #endif

You 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.

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 and warning and info messages

You instruct the compiler to generate user-defined compiler errors and warnings and informational messages.

// #error this is an error message
// #warning this is a warning message
// #info this is an info message

Custom directive

You can used defineDirective to define your own directive.

Taking the built-in directive as an example:

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'

Execution priority of directives