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

@crystal-ball/webpack-base

v11.6.0

Published

Customizable webpack base configuration generator

Downloads

222

Readme


⚙️ Setup

1. Install

npm i -D @crystal-ball/webpack-base

2. Add package.json commands

{
  "scripts": {
    "build": "NODE_ENV=production webpack --mode=production",
    "start": "NODE_ENV=development webpack-dev-server --mode=development"
  }
}

3. Add configuration files

Add configuration files for webpack and Babel to the project root. The @crystal-ball/react-application-prototype is a complete working reference application using this package. Projects require a:

  • .browserslistrc
  • .eslintrc.js
  • babel.config.js
  • webpack.config.js

📦 Project defaults

Out of the box all of the webpack-base loaders and plugins will work with projects that use the default project directory structure:

project
├─ / src
│  └─ / api
│  └─ / components
│  └─ / dux
│  └─ / media
│  │  └─ / icons
│  └─ / styles
│  └─ / utils
│  ├─  index.html
│  ├─  index.js
│  └─  index.scss
├─ / static
│  └─  favicon.ico
├─  .browserslistrc
├─  .eslintrc.js
├─  babel.config.js
└─  webpack.config.js

Directories

  • src - Project source code root directory.
  • src/media/icons - The SVG symbol sprite loader will sprite any SVG icons imported from this directory.
  • src/styles - SCSS files in this directory can be imported with the @ alias from anywhere in the project.
  • src/api, src/components, src/dux and src/utils - Suggested but not required directory structure for organizing application code by domain
  • static - The static folder can be used as an escape hatch for including assets that are not directly imported in the project code. The contents are copied to the output directory during builds.

📝 Configuration API

The project webpack.config.js should call the webpack-base package to generate a base configuration. The base configuration can then be modified in any way to support specific project needs.

// webpack.config.js
const webpackBase = require('@crystal-ball/webpack-base')

module.exports = () => {
  const { configs } = webpackBase(/* options */)

  /*
   * Handle non-standard, advanced project customization by directly updating
   * the generated base configs.
   */
  configs.rules.push({
    /* some custom loader */
  })

  return configs
}

Options

The base configurations generated by the package can be customized by passing an options object:

const { configs } = webpackBase{
  devServer,
  envVars
  paths,
  sassOptions,
  target,
})

Available path configs

const paths = {
  /**
   * Project root directory that is used by webpack (eg to handle resolutions).
   * webpack base attempts to automatically set the project context, but it
   * can help fix resolution errors to specify it.
   * @default /
   */
  context,
  /**
   * SVG files imported from these directories will be loaded+sprited using the
   * `SVGSymbolSprite` package.
   * @default ['/src/media/icons']
   */
  iconSpriteIncludes,
  /**
   * JS files imported from these directories will be loaded using the JS loader.
   * @default ['/src']
   */
  jsLoaderIncludes,
  /**
   * Build assets are emitted to this directory.
   * @default /public
   */
  output,
  /**
   * Application source files directory. This directory is used as a base for
   * the icon includes path.
   * @default /src
   */
  src,
  /**
   * Application public static files directory. This directory is copied to the
   * build without manipulation by the `CopyWebpackPlugin` and provides an
   * escape hatch to include assets in a build without importing them in the
   * application source.
   * @default /static
   */
  static,
}

😍 Featureset

  • JS loader setup to transpile all source in the jsLoaderIncludes with the babel-loader
  • Sourcemaps for dev and prod environments
  • Handles adding scripts to index.html
  • Friendly errors
  • Dev server with hot reloading
  • Progress indicators
  • Production optimizations including uglify and module concatenation
  • Output directory cleaning
  • Injected PUBLIC_PATH for routing
  • DEVTOOL environment variable will override source maps
  • Import paths case is verified to ensure Linux and MacOS compatability
  • Production CSS+JS assets are minified

Caching

Long term asset caching is supported by including content based hashes in the generated asset filenames.

  • [contenthash] substitution is included in filenames in production builds to append a hash that will change when the file contents change
  • A single runtime asset is extracted to deduplicate webpack runtime boilerplate
  • Module ids are deterministically hashed based on content to prevent import order changes causing all chunks to update.
  • Dynamic imports for code splitting should use webpack magic comments to set a semantic asset name.

Environment variable injection

The following environment variables are injected by the build:

| Constant | Usage | | ------------- | ----------------------------------------------------------------------------- | | NODE_ENV | Defaults to match NODE_ENV, used by Babili to strip code in prod builds | | DEBUG | Defaults to false, can be used for adding detailed logging in dev environment | | PUBLIC_PATH | Defaults to '/', useful for importing media and configuring CDN paths |

Additional environment variables can be passed in an envVars option and they will be injected into the build

webpackBase({
  envVars: { TRACKING_ID: 'x-123456' },
})

⚛️ Electron support

Electron renderer processes can be bundled by passing a target flag in options:

// webpack.config.js
const webpackBase = require('@crystal-ball/webpack-base')

module.exports = () => {
  return webpackBase({ target: 'electron-renderer' }).configs
}

By default webpack-base will look for project source files in /src/renderer instead of /src and builds are output to /src/build instead of /dist. This is for working with Electron build systems.

🐳 Docker support

When working within a Docker setup, the dev server port (default 3000) must be exposed and the host set to 0.0.0.0. Including a start command for Docker is recommended:

{
  "start:docker": "NODE_ENV=development webpack-dev-server --host=0.0.0.0 --mode=development"
}

🎛 Accessing resources

The configured loaders and plugins can be accessed directly in the return value, this is useful when setting up Storybook to pass additional loaders and plugins.

// webpack.config.js
const webpackBase = require('@crystal-ball/webpack-base')

module.exports = () => {
  const { loaders, plugins } = webpackBase(/* options */)
}

Returned loaders

config.loaders = {
  jsLoader,
  sassLoader,
  svgSpriteLoader,
  svgComponentLoader,
  fileLoader,
  rawLoader,
}

Returned plugins

config.plugins = {
  progressBarPlugin,
  environmentPlugin,
  htmlPlugin,
  svgSymbolSpritePlugin,
  copyPlugin,
  hotModuleReplacementPlugin,
  friendlyErrorsPlugin,
}

This can be useful for adding loaders to projects like Storybook.

👷‍♀️ Developing

Development and testing of the repository use a Docker workflow to ensure that the generated configs work with the packages required and the minimum version of Node supported:

# Build the image and start the container
npm run container

# Start the webpack-dev-server 🎉
npm run start:docker

✅ Testing

Unit tests are run with Jest and use snapshots to validate the generated configs for development and production environments.

🗺 Roadmap

Interested in contributing? Start here 😍

👍 Contributing

All contributions are greatly appreciated 👍🎉. To contribute please:

Node version support

Node version running inside Atom's Electron instance is support target to ensure users of ESLint import plugin are able to parse these webpack configs.