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

@wuzzle/cli

v0.6.3

Published

Wuzzle command line interface.

Downloads

30

Readme

Provides a unified but opt-in way to config all kinds of webpack based compilation easily 🚀

Why

  1. For compilers with webpack embedded for compilation (like create-react-app, vue-cli, next, nuxt, etc), wuzzle provides the ability of modifying their internally used webpack configs.
  2. For JS runners with their own methods of compilation (like jest, mocha, the bare node, etc), wuzzle can hook up compatible webpack based compilation as replacements.
  3. For file transpilation, wuzzle provides a webpack based transpiler.
  4. For setup process, wuzzle opts in easily.
  5. For modification on webpack configs, wuzzle provides a unified entry, a dry-run mode, and well-tested modification utilities.

Install

npm install --save-dev wuzzle

Usage

Modify internally used webpack configs in compilers

Many compilers embed webpack to do their own compilation. Some of them have their own ideas about compilation customization, like "eject" of create-react-app or "chaining" of vue-cli, which might have bothered you. But now, with wuzzle, you can bypass those contraints and modify the internally used webpack configs directly. Take an example of a project created with create-react-app.

First, prepend command wuzzle to commands react-scripts start, react-scripts build in the package.json:

  "scripts": {
-    "start": "react-scripts start",
+    "start": "wuzzle react-scripts start",
-    "build": "react-scripts build"
+    "build": "wuzzle react-scripts build"
  }

Then, next to the package.json, create a file named wuzzle.config.js exporting a single top-level function, in which you can modify the webpack config used inside react-scripts:

module.exports = (webpackConfig, webpack, wuzzleContext) => {
  // TODO modify the internally used webpack config of the webpack embedded compiler
};

The param wuzzleContext gives the context about the running command so to help with finer control of your modification. For details of fields, see also interface WuzzleModifyOptions in "src/apply-config".

Officially, following compilers are guaranteed to work with wuzzle:

But theoretically, any compilers with webpack embedded for compilation would work with wuzzle. Just prepend command wuzzle to a compiler's command for a try, like wuzzle vue-cli-service build or wuzzle start-storybook.

Hook up webpack based compilation for JS runners

By JS runners, we mean programs that can execute JS files, like test runners or the bare node. They usually have their own methods of compilation, like "transform" of jest or "require.extensions" of the bare node. They don't follow a consistent form. But, with wuzzle, you can hook up webpack based compilation to make it consistent.

The usage is similarly easy. First, prepend command wuzzle to the JS runner's command to hook up webpack based compilation, like wuzzle jest. By default, wuzzle replaces the original compilation with a compatible webpack based compilation. Then again, you can utilize the wuzzle.config.js next to the package.json to adjust the webpack config.

Currently, following JS runners are guaranteed to work with wuzzle:

And, there are some tips worth mentioning, please read as needed:

By node-like JS runners, we mean JS runners that have the same method of compilation as the bare node, like mocha, including the bare node itself. By default, they can only execute .js files. We provide command option -E,--ext to specify the other wanted file extensions to get executed. Please take a try like wuzzle node -E ".js,.jsx,.ts,.tsx" server.ts. By the way, if you are doing file requiring with file extentions omitted, like require('./utils') towards a TS file utils.ts, please make sure the field resolve.extensions of the webpack config is properly set.

As logics inside the webpack based compilation only run asyncly, but JS runners only accept sync file content compilation, wuzzle has to utilize some hacky trick internally to make the former async fit the latter sync. As a result, some performance loss is introduced when webpack based compilaton is hooked up for JS runners. For the remediation, we provide command option --pre-compile which can get the specified files compiled all beforehand in bulk so to minimize the performance loss. Please take a try like wuzzle jest --pre-compile "src/\*_/_.ts?(x)".

On the other hand, in case that you might only want to further customize a JS runner's own method of compilation, wuzzle provides a fallback ability. By far, it's only available for jest-like JS runners. By jest-like JS runners, we mean JS runners that are built on jest, like subcommand test of create-react-app or subcommand test:unit of vue-cli with plugin @vue/cli-plugin-unit-jest, including jest itself. The usage is straightforward, too.

First, add command option --no-webpack while prepending command wuzzle to the jest-like JS runner's command, like wuzzle react-scripts test --no-webpack. Then, with the wuzzle.config.js, instead of a single top-level function, export an object with a funtion field named jest to adjust the jest config:

module.exports = {
  jest(jestConfig, jestInfo, wuzzleContext) {
    // TODO modify the internally used jest config of the jest-like JS runner
  },
};

Notice that, the first param jestConfig is not the same externally used jest config. It's the internally used jest config and please refer to "ProjectConfig" for its data structure.

For details about extended usages that wuzzle provides for JS runners, see also command option -H,--Help, like wuzzle jest -H.

Webpack based file transpilation

With webpack, a regular practice is to generate JS bundles, and file transpilation can be too tedious to do. Though in JS bundles, dynamically accessing source files at runtime can be pretty tricky because the original directory structure gets lost while bundling. Now, to make most of webpack, wuzzle introduces webpack based transpilation with command wuzzle transpile:

$ wuzzle transpile --help

Usage: wuzzle-transpile [options] <globs...>

Options:
  -d, --out-dir <dir>         Compile input files into output directory.
  -w, --watch                 Recompile files on changes.
  --ignore <string>           List of globs not to compile, split by ",". (default: "**/node_modules/**,<absoluteOutDir>/**,**/*.d.ts?(x)")
  -b, --base-path <path>      Resolve input files relative to base path for output subpaths in output directory. (default: longest common path of input files)
  -c, --concurrency <number>  Prevent compiling more than specific amount of files at the same time. (default: os.cpus().length)
  -p, --production            Tell webpack to use production optimization
  -t, --target <string>       Set wepback deployment target. One of "async-node", "electron-main", "electron-renderer", "electron-preload", "node", "node-webkit", "web", or "webworker". (default: "node")
  -s, --source-map [string]   Generate source map. One of "none", "file", or "inline". (default: "none", or "file" if specified without value)
  --no-clean                  Prevent cleaning out directory.
  -F, --follow                Follow symlinked directories when expanding "**" patterns.
  -V, --verbose               Show more details.
  -v, --version               Output the version number.
  -h, --help                  Output usage information.

A typical usage may look like wuzzle transpile "src/**/*" -s -d dist, meanwhile, additionally with command option -p for optimization or -w for watch mode. Again, you can utilize the wuzzle.config.js next to the package.json to modify the internally used webpack config.

Dry-run mode

To view the webpack config modification in the wuzzle.config.js more clearly, here is the dry-run mode, which you can activate by command option --dry-run, like wuzzle react-scripts build --dry-run. The dry-run mode will audit the modification in the wuzzle.config.js, and print the webpack config with diffs, but skip executing the actual execution of the command. It's available along with all the usages of wuzzle above.

Modification utilities on webpack configs

As modifying webpack configs can be quite tedious and sometimes tricky, wuzzle provides you well-tested modification utilities, which can be imported directly from package wuzzle in the wuzzle.config.js, like const { insertBeforeRule } = require('wuzzle');. Every modification utility follows a pattern of "query from the input, then do", which also drives the first 2 params to always be input and query. The full list of those utilities is as below:

import type pathType from 'path';
import type webpackType from 'webpack';

type RuleOpInput =
  | webpackType.Configuration
  | webpackType.Module
  | webpackType.RuleSetRule[]
  | undefined;

interface RuleOpQuery {
  file?: string | string[] | pathType.FormatInputPathObject | pathType.FormatInputPathObject[];
  loader?: string | string[];
}

type UseItem = string | webpackType.RuleSetLoader;

type UseItemOpInput =
  | webpackType.Configuration
  | webpackType.Module
  | webpackType.RuleSetRule[]
  | webpackType.RuleSetRule
  | undefined;

interface UseItemOpQuery {
  loader?: string | string[];
}

/**
 * Return all matched rules. Will go on recursively if rule fields `rules` `oneOf` are found.
 */
function findRules(input: RuleOpInput, query: RuleOpQuery): webpackType.RuleSetRule[];

/**
 * Return all matched use items. Will go on recursively if rule fields `rules` `oneOf` are found.
 */
function findUseItems(input: UseItemOpInput, query: UseItemOpQuery): UseItem[];

/**
 * Returns the first result of `findRules`.
 */
function firstRule(input: RuleOpInput, query: RuleOpQuery): webpackType.RuleSetRule | undefined;

/**
 * Returns the first result of `findUseItems`.
 */
function firstUseItem(input: UseItemOpInput, query: UseItemOpQuery): UseItem | undefined;

/**
 * Insert new rules before the first recursively matched rule
 */
function insertBeforeRule(
  input: RuleOpInput,
  query: RuleOpQuery,
  ...newRules: webpackType.RuleSetRule[]
): boolean;

/**
 * Insert new use items before the first recursively matched use item
 */
function insertBeforeUseItem(
  input: UseItemOpInput,
  query: UseItemOpQuery,
  ...newUseItems: webpackType.RuleSetUseItem[]
): boolean;

/**
 * Insert new rules after the first recursively matched rule
 */
function insertAfterRule(
  input: RuleOpInput,
  query: RuleOpQuery,
  ...newRules: webpackType.RuleSetRule[]
): boolean;

/**
 * Insert new use items after the first recursively matched use item
 */
function insertAfterUseItem(
  input: UseItemOpInput,
  query: UseItemOpQuery,
  ...newUseItems: webpackType.RuleSetUseItem[]
): boolean;

/**
 * Replace the first recursively matched rule with new rules
 */
function replaceRule(
  input: RuleOpInput,
  query: RuleOpQuery,
  ...newRules: webpackType.RuleSetRule[]
): boolean;

/**
 * Replace the first recursively matched use item with new use item
 */
function replaceUseItem(
  input: UseItemOpInput,
  query: UseItemOpQuery,
  ...newUseItems: webpackType.RuleSetUseItem[]
): boolean;

/**
 * Delete the first recursively matched rule
 */
function deleteRule(input: RuleOpInput, query: RuleOpQuery): boolean;

/**
 * Delete the first recursively matched use item
 */
function deleteUseItem(input: UseItemOpInput, query: UseItemOpQuery): boolean;

The keywords rule and use item are webpack concepts. The former defines the primary part of the compilation and the latter defines the concretes of the former. The query fields, file and loader, decide how to find the target. The former is to query a rule that matches the give file path and the latter is to query a rule or a use item that contains a loader matching the given loader name. Notice that, values of different query fields are applied in the behavior of logical OR but values of a same query field are applied in the bahavior of logical AND. For example, a query value of { file: 'index.ts', loader: ['a-loader', 'b-loader'] } is to query a rule that matches file path index.ts OR contains loaders matching loader names a-loader AND b-loader.

Realworld Examples

If you are interested in how wuzzle works in the real world, we have a realworld app built on the React app created with create-react-app, which contains scripts of build, watch, unit test, end-to-end test, lint and launch. The app is preapred for the purpose of e2e testing and it's able to serve as a realworld example, too. Please take a look at "e2e/.../react-scripts" if needed.

Contributing

If you met any problems, just reach out to us with the issue tracker. It's either good in English or Chinese. If you'd like to take part in the development yourself, please see also CONTRIBUTING.md. Welcome any contributors!