⚙️ 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.
const webpackBase = require('@crystal-ball/webpack-base')
module.exports = () => {
const { configs } = webpackBase()
configs.rules.push({
})
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 = {
context,
iconSpriteIncludes,
jsLoaderIncludes,
output,
src,
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:
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.
const webpackBase = require('@crystal-ball/webpack-base')
module.exports = () => {
const { loaders, plugins } = webpackBase()
}
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:
npm run container
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.