npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@qinzisong/webpack-preprocessor-loader

v1.5.0

Published

A code preprocessor for Webpack

Downloads

3

Readme

webpack-preprocessor-loader

Version Node Downloads License Build Status

Bring the awesome "Conditional Compilation" to the Webpack, and more.

Why

Make life easy with the help of webpack-preprocessor-loader !

Now leverage the full power of Conditional Compilation in Webpack to output specific codes based on conditional directives. By which you could:

  • Hide specific contents from the final result;
  • Import different packages by environment (eg: development/production);
  • Remove debugs in production;
  • Split codes in production, while bundle them in development;
  • Many other scenarios...

Simply write:

// #!if ENV === 'develop'
import someModule from 'module-name';
// #!else
const anotherModule = import('another-module-name');
// #!endif

// #!debug
console.log(someModule);

/*
 * My precious code!
 * #!secret
 */
const the_answer_to_everything = '42';

...which yields:

ENV === 'product', debug === false, secret === false

const anotherModule = import('another-module-name');

Also with build-in JSX/HTML comment syntax support. See Usage.

Pros:

  • It is "Conditional Compilation";
  • Say goodbye to those "process.env.NODE_ENV"s messing around the code;
  • Deals directly with raw text, so it just works on any text-based file;
  • Create custom directives if needed;

Cons:

  • Maybe a little verbose in some cases;

    If so, consider using webpack.DefinePlugin backwards.

Compatibility

  • webpack: 4.x+
  • node: 6.11.5 minimum (aligned with webpack 4)

Installation

yarn add webpack-preprocessor-loader -D

or

npm install webpack-preprocessor-loader -D

Configuration

Since it deals directly with the raw text, webpack-preprocessor-loader should be the last loader in use definition:

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          'babel-loader',
          {
            loader: 'webpack-preprocessor-loader',
            options: {
              debug: process.env.NODE_ENV !== 'product',
              directives: {
                secret: false,
              },
              params: {
                ENV: process.env.NODE_ENV,
              },
              verbose: false,
            },
          },
        ],
      },
    ],
  },
};

Usage

Note that any text-based file can be compiled, not only codes, for example:

  • HTML/Pug/...
  • Sass/Less/...
  • Json5/Xml/Yaml/...

Basics

Conditional Compilation relies on a series of specified directives to decide code emitting strategy. The directive must be wrapped in a comment, followed with "#!".

Demo in Javascript:

// Nope. Wrap it in a comment.
'#!debug';

// Depends on the value provided in options.debug...
// #!debug
const a = 1; // ...this line may be omitted.

// What about a custom directive? 
// Add a property on options.directives, say "secret", and set it to `false`
// #!secret
const b = 1; // ...this line will be omitted.

// Works like real "if-else"!
// But first set a value on options.params, say "options.params.foo = 1"
// #!if foo === 1
const c = 1; //
/* #!else */ // <-- Also legal.
const c = 2;
// And always remember to close it by...
// #!endif

// Now try to find your own usage!

More detailed explanations see examples provided in Options and Build-in Directives.

JSX comment syntax (^1.0.4)

import React from 'react';

/* #!debug */
console.log('wow');

function Hello() {
  return <div>
    {/* #!debug */}
    <p>oops</p>

    {/* #!if stage === 'product' */}
    <p>Ready to go</p>
    {/* #!endif */}
  </div>;
}

HTML comment syntax (^1.1.0)

<body>
  <!-- #!debug -->
  <p>oops</p>

  <!-- #!if stage === 'product' -->
  <p>Ready to go</p>
  <!-- #!endif -->
</body>

Inline directive within comment (^1.1.0)

See below.

Multiline directive syntax (^1.1.0)

See below.

Multiline directive syntax with comment (^1.1.0)

The following syntax are equivalent and legal:

// #!if stage === 'product'
/* #!if stage === 'product' */

/*
  #!if stage === 'product'
*/

/*
 * Look mom I have a comment!
 * #!if stage === 'product'
 */

// I have a comment too. #!if stage === 'product'

Options

debug _

type: boolean

default: false

Provide constant value for build-in #!debug directive. See Directives - #!debug.

directives

type: {[key: string]: boolean}

default: {}

Define custom directives. For example, to create a directive called "secret":

// In webpack config...

{
  loader: 'webpack-preprocessor-loader',
  options: {
    directives: {
      secret: false,
    },
  },
},

In code:

// #!secret
console.log('wow'); // This line will be omitted

Note that the custom directive only affects its next line, which means:

// #!secret
console.log('Removed'); // This line will be omitted
console.log('Kept'); // This line will not be affected by "#!secret", hence it will be kept anyway

If an undefined directive is referenced, say "foo", the next line marked by #!foo will always be omitted, because the value of foo is undefined, identical as false.

params

type: {[key: string]: any}

default: {}

Provide constant values for build-in #!if / #!elseif / #!else / #!endif directives. See Directives - #!if / #!else / #!elseif / #!endif

verbose

type: boolean

default: false

Whether to keep raw info or not. Basically for debugging purpose.

// options.params.ENV === 'product'

// #!if ENV === 'develop'
console.log('many doge');
// #!else
console.log('much wow');
// #!endif

If set to true, yields:

// #!if ENV === 'develop'
// console.log('many doge');
// #!else
console.log('much wow');
// #!endif

Build-in Directives

#!if / #!else / #!elseif / #!endif

Basic Usage

As name suggests, these directives work similarly like real if logic:

// In webpack config...

{
  loader: 'webpack-preprocessor-loader',
  options: {
    params: {
      foo: 2,
      bar: 1,
    },
  },
},

The following code...

// #!if foo === 1
const a = 1;
// #!elseif bar === 1
const a = 2;
// #!elseif bar === 2
const a = 3;
// #!else
const a = 4;
// #!endif

...yields

const a = 2;

Any valid #!if / #!else / #!elseif / #!endif combination is accepted, only remember always close selection statements by #!endif.

Advanced Condition

The condition can also be some more complex expressions. For example:

// #!if foo === 1 && bar === 2

// #!if foo + bar === 3

// Seriously?
// #!if (function(a){ return a === 1; })(foo)

Behind the scenes, the expression is wrapped in a return clause, and dynamically evaluated during compilation, thus its context is irrelevant to the code. So all variables in the expression should be pre-defined in the params and treated as constants. Ensure the expression returns a boolean value.

#!debug

A semantic and handy directive to mark specific line only to be kept when needed. For example:

// options.debug === false

// #!debug
console.log('test'); // This line will be omitted

Note that the #!debug directive only affects its next line, which means:

// options.debug === false

// #!debug
console.log('Removed'); // This line will be omitted
console.log('Kept'); // This line will not be affected by "#!debug", hence it will be kept anyway

Caveats

Inline directive with code

The following code may not work as expected:

// debug === false
const foo = 1; /* #!debug */    // <-- the directive will be ignored and this line will be kept
const bar = 2;                  // <-- this line will be kept anyway

// or

// debug === true
/* #!debug */ const foo = 1;    // <-- this line will be omitted anyway
const bar = 2;

So please make sure not mix directive and code on the same line.

Linting

The following code yields errors during linting:

// #!if ENV = 'develop'
const foo = 1; 
// #!else
const foo = -1; 
// #!endif

// "[ts] Cannot redeclare block-scoped variable 'foo'."
// "[eslint] Parsing error: Identifier 'foo' has already been declared"

Typescript

To suppress the error, a tricky way is simply adding // @ts-ignore before all declarations:

// #!if ENV = 'develop'
// @ts-ignore
const foo = 1;
// #!else
// @ts-ignore
const foo = -1;
// #!endif

// Errors gone.

ESlint

It is hard to get around this problem while linting through editor plugin, because ESLint parses the file into AST first, which caused a parsing error. So the only solution is to temporarily comment one or more declarations out during code editing.

Otherwise, if eslint-loader is used, simply put it before webpack-preprocessor-loader:

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          'babel-loader',
          'eslint-loader',
          {
            loader: 'webpack-preprocessor-loader',
            options: {
              // ...
            },
          },
        ],
      },
    ],
  },
};

License

MIT License