1 | <div align="right">
|
2 | <h1 align="right">
|
3 | <img height=75 src="./docs/assets/readme-header.png" alt="webpack base">
|
4 | </h1>
|
5 |
|
6 |
|
7 | <a href="https://www.npmjs.com/package/@crystal-ball/webpack-base">
|
8 | <img src="https://img.shields.io/npm/v/@crystal-ball/webpack-base" alt="Package version" valign="text-top"/>
|
9 | </a>
|
10 | <a href="https://www.npmjs.com/package/@crystal-ball/webpack-base">
|
11 | <img src="https://img.shields.io/npm/dt/@crystal-ball/webpack-base?color=blue" alt="NPM downloads" valign="text-top" />
|
12 | </a>
|
13 | <a href="https://github.com/crystal-ball/webpack-base/actions?workflow=CI%2FCD">
|
14 | <img src="https://github.com/crystal-ball/webpack-base/workflows/CI%2FCD/badge.svg" alt="Build status" valign="text-top" />
|
15 | </a>
|
16 | <a href="https://snyk.io/test/github/crystal-ball/webpack-base?targetFile=package.json">
|
17 | <img src="https://snyk.io/test/github/crystal-ball/webpack-base/badge.svg?targetFile=package.json" alt="Known vulnerabilities" valign="text-top" />
|
18 | </a>
|
19 | <a href="https://codeclimate.com/github/crystal-ball/webpack-base/test_coverage">
|
20 | <img src="https://api.codeclimate.com/v1/badges/eee860e3bd1519dacf5e/test_coverage" alt="Test coverage" valign="text-top" />
|
21 | </a>
|
22 | <a href="https://codeclimate.com/github/crystal-ball/webpack-base/maintainability">
|
23 | <img src="https://api.codeclimate.com/v1/badges/eee860e3bd1519dacf5e/maintainability" alt="Maintainability" valign="text-top" />
|
24 | </a>
|
25 | <code>:status </code>
|
26 |
|
27 | <br />
|
28 | <a href="https://renovatebot.com/">
|
29 | <img src="https://img.shields.io/badge/Renovate-enabled-32c3c2.svg" alt="Renovate" valign="text-top" />
|
30 | </a>
|
31 | <a href="https://commitizen.github.io/cz-cli/">
|
32 | <img src="https://img.shields.io/badge/Commitizen-%E2%9C%93%20friendly-10e67b" alt="Commitizen friendly" valign="text-top" />
|
33 | </a>
|
34 | <a href="https://github.com/crystal-ball/webpack-base#workspaces/-projects-5b88b5c9af3c0a2186966767/board?repos=136812233">
|
35 | <img src="https://img.shields.io/badge/ZenHub-managed-5e60ba.svg" alt="ZenHub" valign="text-top" />
|
36 | </a>
|
37 | <a href="https://semantic-release.gitbook.io/semantic-release/">
|
38 | <img src="https://img.shields.io/badge/%F0%9F%93%A6%F0%9F%9A%80-semantic_release-e10079.svg" alt="Semantic Release" valign="text-top"/>
|
39 | </a>
|
40 | <a href="./CODE_OF_CONDUCT.md">
|
41 | <img src="https://img.shields.io/badge/Contributor%20Covenant-v2.0-de8cf2.svg" alt="Contributor Covenant" valign="text-top" />
|
42 | </a>
|
43 | <code>:integrations</code>
|
44 |
|
45 | <br />
|
46 | <a href="https://github.com/crystal-ball">
|
47 | <img src="https://img.shields.io/badge/%F0%9F%94%AE%E2%9C%A8-contains_magic-D831D7.svg" alt="Contains magic" valign="text-top" />
|
48 | </a>
|
49 | <a href="https://github.com/crystal-ball/crystal-ball.github.io">
|
50 | <img src="https://img.shields.io/badge/%F0%9F%92%96%F0%9F%8C%88-full_of_love-F5499E.svg" alt="Full of love" valign="text-top" />
|
51 | </a>
|
52 | <code>:flair </code>
|
53 |
|
54 |
|
55 | <h1></h1>
|
56 | <br />
|
57 | <p align="center">
|
58 | <em>This package generates a base webpack configuration and dependencies for
|
59 | React web and Electron applications. Users can customize the generated base
|
60 | configurations to meet the specific needs of any project.</em>
|
61 | </p>
|
62 | <br />
|
63 | </div>
|
64 |
|
65 | - [Setup](#-setup) - Installation and file setup instructions
|
66 | - [Project defaults](#=project-defaults) - Documentation on default project
|
67 | structure used
|
68 | - [Configuration API](#-configuration-api) - Documentation on customizing
|
69 | generated configurations
|
70 | - [Featureset](#-featureset) - Overview of the supported magic
|
71 | - [Electron support](#-electron-support) - Using within an Electron project
|
72 | - [Docker support](#-docker-support) - Using within a Docker workflow
|
73 | - [Accessing resources](#-accessing-resources) - Accessing loaders and plugins
|
74 | directly
|
75 | - [Developing](#-developing) - How to develop the project
|
76 | - [Testing](#-testing) - How to test the project
|
77 | - [Roadmap](#-roadmap) - TODO items and contributing suggestions
|
78 | - [Contributing](#-contributing) - Yes please! 😍
|
79 |
|
80 | ---
|
81 |
|
82 | ## ⚙️ Setup
|
83 |
|
84 | **1. Install**
|
85 |
|
86 | ```bash
|
87 | npm i -D @crystal-ball/webpack-base
|
88 | ```
|
89 |
|
90 | **2. Add `package.json` commands**
|
91 |
|
92 | ```json
|
93 | {
|
94 | "scripts": {
|
95 | "build": "NODE_ENV=production webpack --mode=production",
|
96 | "start": "NODE_ENV=development webpack-dev-server --mode=development"
|
97 | }
|
98 | }
|
99 | ```
|
100 |
|
101 | **3. Add configuration files**
|
102 |
|
103 | Add configuration files for webpack and Babel to the project root. The
|
104 | [@crystal-ball/react-application-prototype][] is a complete working reference
|
105 | application using this package. Projects require a:
|
106 |
|
107 | - `.browserslistrc`
|
108 | - `.eslintrc.js`
|
109 | - `babel.config.js`
|
110 | - `webpack.config.js`
|
111 |
|
112 | ## 📦 Project defaults
|
113 |
|
114 | Out of the box all of the webpack-base loaders and plugins will work with
|
115 | projects that use the default project directory structure:
|
116 |
|
117 | ```
|
118 | project
|
119 | ├─ / src
|
120 | │ └─ / api
|
121 | │ └─ / components
|
122 | │ └─ / dux
|
123 | │ └─ / media
|
124 | │ │ └─ / icons
|
125 | │ └─ / styles
|
126 | │ └─ / utils
|
127 | │ ├─ index.html
|
128 | │ ├─ index.js
|
129 | │ └─ index.scss
|
130 | ├─ / static
|
131 | │ └─ favicon.ico
|
132 | ├─ .browserslistrc
|
133 | ├─ .eslintrc.js
|
134 | ├─ babel.config.js
|
135 | └─ webpack.config.js
|
136 | ```
|
137 |
|
138 | ### Directories
|
139 |
|
140 | - **src** - Project source code root directory.
|
141 | - **src/media/icons** - The SVG symbol sprite loader will sprite any SVG icons
|
142 | imported from this directory.
|
143 | - **src/styles** - SCSS files in this directory can be imported with the `@`
|
144 | alias from anywhere in the project.
|
145 | - **src/api**, **src/components**, **src/dux** and **src/utils** - Suggested but
|
146 | not required directory structure for organizing application code by domain
|
147 | - **static** - The static folder can be used as an escape hatch for including
|
148 | assets that are not directly imported in the project code. The contents are
|
149 | copied to the output directory during builds.
|
150 |
|
151 | ## 📝 Configuration API
|
152 |
|
153 | The project `webpack.config.js` should call the webpack-base package to generate
|
154 | a base configuration. The base configuration can then be modified in any way to
|
155 | support specific project needs.
|
156 |
|
157 | ```javascript
|
158 | // webpack.config.js
|
159 | const webpackBase = require('@crystal-ball/webpack-base')
|
160 |
|
161 | module.exports = () => {
|
162 | const { configs } = webpackBase(/* options */)
|
163 |
|
164 | /*
|
165 | * Handle non-standard, advanced project customization by directly updating
|
166 | * the generated base configs.
|
167 | */
|
168 | configs.rules.push({
|
169 | /* some custom loader */
|
170 | })
|
171 |
|
172 | return configs
|
173 | }
|
174 | ```
|
175 |
|
176 | ### Options
|
177 |
|
178 | The base configurations generated by the package can be customized by passing an
|
179 | options object:
|
180 |
|
181 | ```javascript
|
182 | const { configs } = webpackBase{
|
183 | devServer,
|
184 | envVars
|
185 | paths,
|
186 | sassOptions,
|
187 | target,
|
188 | })
|
189 | ```
|
190 |
|
191 | ### Available path configs
|
192 |
|
193 | ```javascript
|
194 | const paths = {
|
195 | /**
|
196 | * Project root directory that is used by webpack (eg to handle resolutions).
|
197 | * webpack base attempts to automatically set the project context, but it
|
198 | * can help fix resolution errors to specify it.
|
199 | * @default /
|
200 | */
|
201 | context,
|
202 | /**
|
203 | * SVG files imported from these directories will be loaded+sprited using the
|
204 | * `SVGSymbolSprite` package.
|
205 | * @default ['/src/media/icons']
|
206 | */
|
207 | iconSpriteIncludes,
|
208 | /**
|
209 | * JS files imported from these directories will be loaded using the JS loader.
|
210 | * @default ['/src']
|
211 | */
|
212 | jsLoaderIncludes,
|
213 | /**
|
214 | * Build assets are emitted to this directory.
|
215 | * @default /public
|
216 | */
|
217 | output,
|
218 | /**
|
219 | * Application source files directory. This directory is used as a base for
|
220 | * the icon includes path.
|
221 | * @default /src
|
222 | */
|
223 | src,
|
224 | /**
|
225 | * Application public static files directory. This directory is copied to the
|
226 | * build without manipulation by the `CopyWebpackPlugin` and provides an
|
227 | * escape hatch to include assets in a build without importing them in the
|
228 | * application source.
|
229 | * @default /static
|
230 | */
|
231 | static,
|
232 | }
|
233 | ```
|
234 |
|
235 | ## 😍 Featureset
|
236 |
|
237 | - JS loader setup to transpile all source in the `jsLoaderIncludes` with the
|
238 | `babel-loader`
|
239 | - Sourcemaps for dev and prod environments
|
240 | - Handles adding scripts to `index.html`
|
241 | - Friendly errors
|
242 | - Dev server with hot reloading
|
243 | - Progress indicators
|
244 | - Production optimizations including uglify and module concatenation
|
245 | - Output directory cleaning
|
246 | - Injected `PUBLIC_PATH` for routing
|
247 | - `DEVTOOL` environment variable will override source maps
|
248 | - Import paths case is verified to ensure Linux and MacOS compatability
|
249 | - Production CSS+JS assets are minified
|
250 | - Application logo is used to generate and inject favicon resources in build
|
251 |
|
252 | ### Caching
|
253 |
|
254 | Long term asset caching is supported by including content based hashes in the
|
255 | generated asset filenames.
|
256 |
|
257 | - `[contenthash]` substitution is included in filenames in production builds to
|
258 | append a hash that will change when the file contents change
|
259 | - A single runtime asset is extracted to deduplicate webpack runtime boilerplate
|
260 | - Module ids are hashed based on content to prevent import order changes causing
|
261 | all chunks to update.
|
262 | - Dynamic imports for code splitting should use webpack magic comments to set a
|
263 | semantic asset name.
|
264 |
|
265 | ### Environment variable injection
|
266 |
|
267 | The following environment variables are injected by the build:
|
268 |
|
269 | | Constant | Usage |
|
270 | | ------------- | ----------------------------------------------------------------------------- |
|
271 | | `NODE_ENV` | Defaults to match NODE_ENV, used by Babili to strip code in prod builds |
|
272 | | `DEBUG` | Defaults to false, can be used for adding detailed logging in dev environment |
|
273 | | `PUBLIC_PATH` | Defaults to '/', useful for importing media and configuring CDN paths |
|
274 |
|
275 | Additional environment variables can be passed in an `envVars` option and they
|
276 | will be injected into the build
|
277 |
|
278 | ```js
|
279 | webpackBase({
|
280 | envVars: { TRACKING_ID: 'x-123456' },
|
281 | })
|
282 | ```
|
283 |
|
284 | ## ⚛️ Electron support
|
285 |
|
286 | Electron renderer processes can be bundled by passing a `target` flag in
|
287 | options:
|
288 |
|
289 | ```javascript
|
290 | // webpack.config.js
|
291 | const webpackBase = require('@crystal-ball/webpack-base')
|
292 |
|
293 | module.exports = () => {
|
294 | return webpackBase({ target: 'electron-renderer' }).configs
|
295 | }
|
296 | ```
|
297 |
|
298 | By default `webpack-base` will look for project source files in `/src/renderer`
|
299 | instead of `/src` and builds are output to `/src/build` instead of `/dist`. This
|
300 | is for working with Electron build systems.
|
301 |
|
302 | ## 🐳 Docker support
|
303 |
|
304 | When working within a Docker setup, the dev server port (default `3000`) must be
|
305 | exposed and the host set to `0.0.0.0`. Including a start command for Docker is
|
306 | recommended:
|
307 |
|
308 | ```json
|
309 | {
|
310 | "start:docker": "NODE_ENV=development webpack-dev-server --host=0.0.0.0 --mode=development"
|
311 | }
|
312 | ```
|
313 |
|
314 | ## 🎛 Accessing resources
|
315 |
|
316 | The configured loaders and plugins can be accessed directly in the return value,
|
317 | this is useful when setting up Storybook to pass additional loaders and plugins.
|
318 |
|
319 | ```javascript
|
320 | // webpack.config.js
|
321 | const webpackBase = require('@crystal-ball/webpack-base')
|
322 |
|
323 | module.exports = () => {
|
324 | const { loaders, plugins } = webpackBase(/* options */)
|
325 | }
|
326 | ```
|
327 |
|
328 | #### Returned loaders
|
329 |
|
330 | ```js
|
331 | config.loaders = {
|
332 | jsLoader,
|
333 | sassLoader,
|
334 | svgSpriteLoader,
|
335 | svgComponentLoader,
|
336 | fileLoader,
|
337 | rawLoader,
|
338 | }
|
339 | ```
|
340 |
|
341 | #### Returned plugins
|
342 |
|
343 | ```js
|
344 | config.plugins = {
|
345 | progressBarPlugin,
|
346 | environmentPlugin,
|
347 | htmlPlugin,
|
348 | svgSymbolSpritePlugin,
|
349 | copyPlugin,
|
350 | hotModuleReplacementPlugin,
|
351 | friendlyErrorsPlugin,
|
352 | }
|
353 | ```
|
354 |
|
355 | This can be useful for adding loaders to projects like Storybook.
|
356 |
|
357 | ## 👷♀️ Developing
|
358 |
|
359 | Development and testing of the repository use a Docker workflow to ensure that
|
360 | the generated configs work with the packages required and the minimum version of
|
361 | Node supported:
|
362 |
|
363 | ```sh
|
364 | # Build the image and start the container
|
365 | npm run container
|
366 |
|
367 | # Start the webpack-dev-server 🎉
|
368 | npm run start:docker
|
369 | ```
|
370 |
|
371 | ## ✅ Testing
|
372 |
|
373 | Unit tests are run with Jest and use snapshots to validate the generated configs
|
374 | for development and production environments.
|
375 |
|
376 | ## 🗺 Roadmap
|
377 |
|
378 | _Interested in contributing? Start here 😍_
|
379 |
|
380 | - [ ] Investigate usage of [profile][] in builds
|
381 | - [ ] Investigate including [Bundle Buddy][bundle] plugin
|
382 |
|
383 | ## 👍 Contributing
|
384 |
|
385 | All contributions are greatly appreciated 👍🎉. To contribute please:
|
386 |
|
387 | - Review the repo [Code of Conduct](./CODE_OF_CONDUCT.md), it is not just for
|
388 | show!
|
389 | - Review the [Contributing Guide](./CONTRIBUTING.md) for a helpful code overview
|
390 | and repository pull request process details.
|
391 |
|
392 | ### Node version support
|
393 |
|
394 | Node version running inside Atom's Electron instance is support target to ensure
|
395 | users of ESLint import plugin are able to parse these webpack configs.
|
396 |
|
397 |
|
398 |
|
399 | [bundle]: https://github.com/samccone/bundle-buddy
|
400 | [@crystal-ball/react-application-prototype]: https://github.com/crystal-ball/react-application-prototype
|
401 | [profile]: https://webpack.js.org/configuration/other-options/#profile
|
402 |
|