Coder Social home page Coder Social logo

kejunmao / unplugin-preprocessor-directives Goto Github PK

View Code? Open in Web Editor NEW
46.0 2.0 3.0 186 KB

preprocessor directives for jsx,tsx,js,ts,html,css,vue and more

License: MIT License

HTML 1.60% TypeScript 98.02% JavaScript 0.38%
conditional-compilation directives esbuild preprocessor rollup unplugin vite webpack

unplugin-preprocessor-directives's Introduction

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
// vite.config.ts
import PreprocessorDirectives from 'unplugin-preprocessor-directives/vite'

export default defineConfig({
  plugins: [
    PreprocessorDirectives({ /* options */ }),
  ],
})

Example: playground/


Rollup
// rollup.config.js
import PreprocessorDirectives from 'unplugin-preprocessor-directives/rollup'

export default {
  plugins: [
    PreprocessorDirectives({ /* options */ }),
  ],
}


Webpack
// webpack.config.js
module.exports = {
  /* ... */
  plugins: [
    require('unplugin-preprocessor-directives/webpack')({ /* options */ })
  ]
}


Nuxt
// nuxt.config.js
export default defineNuxtConfig({
  modules: [
    ['unplugin-preprocessor-directives/nuxt', { /* options */ }],
  ],
})

This module works for both Nuxt 2 and Nuxt Vite


Vue CLI
// vue.config.js
module.exports = {
  configureWebpack: {
    plugins: [
      require('unplugin-preprocessor-directives/webpack')({ /* options */ }),
    ],
  },
}


esbuild
// esbuild.config.js
import { build } from 'esbuild'
import PreprocessorDirectives from 'unplugin-preprocessor-directives/esbuild'

build({
  plugins: [PreprocessorDirectives()],
})


Rspack (⚠️ experimental)
// 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:

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

Conditional compilation

  • #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 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: Generates an error.
  • #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 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

  • pre: Execute as early as possible
  • post: Execute as late as possible

unplugin-preprocessor-directives's People

Contributors

kejunmao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

unplugin-preprocessor-directives's Issues

Import error with webpack

node:internal/modules/esm/resolve:853
  throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
        ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'vite' imported from /Volumes/Extra/Code/conditional/node_modules/.pnpm/[email protected]/node_modules/unplugin-preprocessor-directives/dist/chunk-C3KB5XGL.js
    at packageResolve (node:internal/modules/esm/resolve:853:9)
    at moduleResolve (node:internal/modules/esm/resolve:910:20)
    at defaultResolve (node:internal/modules/esm/resolve:1130:11)
    at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:396:12)
    at ModuleLoader.resolve (node:internal/modules/esm/loader:365:25)
    at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:240:38)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:85:39)
    at link (node:internal/modules/esm/module_job:84:36) {
  code: 'ERR_MODULE_NOT_FOUND'
}

Node.js v20.11.1
 ELIFECYCLE  Command failed with exit code 1.
       Error The "beforeDevCommand" terminated with a non-zero status code.

nextjs config:

/** @type {import('next').NextConfig} */
import PreprocessorDirectives from 'unplugin-preprocessor-directives/webpack'

const nextConfig = {
    output: 'export',
    webpack: (config) => {
        config.plugins = config.plugins || []
        config.plugins.push(new PreprocessorDirectives({}))
        return config
    }
};

export default nextConfig;

This plugin breaks vitest coverage report

When using this plugin and adding // #v-ifdef DEV and // #v-endif comments in my code, vitest marks all code as 100% covered (istanbul).

image

If I remove the directives, the coverage works again:

image

Similar issues can be found at:

  1. unplugin/unplugin-vue-components#333
  2. unplugin/unplugin-vue-components#219 (maybe related, this is referred to in the previous link)

This should be easily reproducible.

Here is a minimal reproduction: https://stackblitz.com/edit/vitest-dev-vitest-4tlh7n?file=src%2Findex.ts

Is there a workaround to solve this problem?

Cannot read properties of undefined (reading 'match') error when using comments without space before text

Hi,
after upgrading to version 1.0.0 (and also the latest 1.0.2) I'm getting the following error using the vite plugin (unplugin-preprocessor-directives/vite)

Cannot read properties of undefined (reading 'match')

After some testing, I found that this error seems to occur if a javascript comment does not contain a space after "//".
This comment creates an error : "//error comment", while this works without any issue "// working comment".
I've also created a playground demonstrating the issue at stackblitz:
https://stackblitz.com/edit/vitejs-vite-hy77nf?file=package.json,src%2FApp.vue
(Comment is in App.vue)

Thanks.

Edit: After rechecking stackblitz with Firefox I get an erorr saying "comment is undefined", Chrome shows the error above.

In vue-cli5, plugin will conflict with html-webpack-plugin.

When I using this plugin with vue-cli5, vue-cli-service serve and vue-cli-service build will throw error:

Error: Child compilation failed:
  Module parse failed: Unexpected token (1:0)
  File was processed with these loaders:
   * ./node_modules/.pnpm/[email protected][email protected]/node_modules/html-webpack-plugin/lib/loader.js
   * ./node_modules/.pnpm/[email protected]/node_modules/unplugin/dist/webpack/loaders/transform.js
  You may need an additional loader to handle the result of these loaders.
  > <!DOCTYPE html>
  | <html lang="">
  |   <head>

I found html-webpack-plugin/lib/loader.js will check if there is any other loader, if exists it will return unmodified source, which cause error.
After some dig, I found add transformInclude hook and /\.html/ to plugin exclude config, unplugin will not create the loader which conflict with html-webpack-plugin and solve issue. But it also mean this plugin cant process html code. Maybe there is better way to fix this?

Sourcemaps always report position 0

In this function the sourcemap positions are always returned as position 0. This breaks mapping back to the original source and coverage reporting.

transformWithMap(code: string, _id: string) {

  transformWithMap(code: string, _id: string) {
    const generated = this.transform(code, _id)
    if (generated) {
      const ms = new MagicString(code, { filename: _id })
      ms.overwrite(0, code.length, generated)
      return {
        code: ms.toString(),
        map: ms.generateMap({ hires: true }),
      }
    }
  }

A simpler reproducible example (effectively the same code):

import MagicString from 'magic-string';

const code = `const answer = 42;\n\nconsole.log("The answer is", answer);`;
const generated = code;

const ms = new MagicString(code, { filename: 'test.ts' })
ms.overwrite(0, code.length, generated)
console.log(ms.generateMap({ hires: true }));

Returns:

SourceMap {
  version: 3,
  file: undefined,
  sources: [ '' ],
  sourcesContent: undefined,
  names: [],
  mappings: 'AAAA;AAAA'
}

AAAA is position 0 for both statements.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.