I made a simple template for myself, but maybe it could be helpful for others.
webpack- Module and asset bundlerwebpack-cli- Command line interface for webpackwebpack-dev-server- Development server for webpack with live reloadingwebpack-merge- Combines a common configuration with a specific one for development or production
babel-loader- This loader allows transpiling JavaScript files using Babel and webpacksass-loader- Load Sass/SCSS and compile it to CSSsass- is a pure JavaScript implementation of Sass
postcss-loader- Loader to process CSS with PostCSScss-loader- Resolve CSS imports & CSS modulesstyle-loader- Inject CSS into the DOM@svgr/webpack- Webpack loader for SVG
html-webpack-plugin- Generate HTML files from templatemini-css-extract-plugin- Extract CSS into separate filesProgressPlugin- This plugin provides a way to customize how progress is reported during a compilation. (You do not need to install this plugin. Webpack comes with this plugin out of the box.). You can also replace this plugin withwebpackbarwhich has more friendly UI.EnvironmentPlugin- injectprocess.envvariables in your output code. (You do not need to install this plugin. Webpack comes with this plugin out of the box.). You can also replace this plugin withwebpack.DefinePluginif you need more control over inserted values.copy-webpack-plugin- Copies individual files or entire directories, which already exist, to the build directory (Only in production mode)css-minimizer-webpack-plugin- Optimize and minimize CSS assets (Only in production mode)terser-webpack-plugin- This plugin uses terser to minify your JavaScript (You do not need to install this plugin. Webpack v5 comes with the latest terser-webpack-plugin out of the box.) (Only in production mode)@rsdoctor/webpack-plugin- Visualize the building process (Only in production mode)@sentry/webpack-plugin- Automatically upload source maps to Sentry and create releases for error tracking and performance monitoring (Only in production mode)eslint-webpack-plugin- is an ESLint plugin for webpack (Only in development mode)fork-ts-checker-webpack-plugin- Webpack plugin that runs typescript type checker on a separate process (Only in development mode)@pmmmwh/react-refresh-webpack-plugin- enable "Fast Refresh" (also previously known as Hot Reloading) for React components. Work closely together withreact-refresh(Only in development mode)
@babel/core- Babel compiler corecore-js- Modular standard library for JavaScript. Includes polyfills for ECMAScript@babel/runtime- is a library that contains Babel modular runtime helpers (such as createClass, regeneratorRuntime and other). Work closely together with@babel/plugin-transform-runtime
-
@babel/preset-env- is a smart preset that allows you to use the latest JavaScript without needing to micromanage which syntax transforms (and optionally, browser polyfills) are needed by your target environment(s). Interacts with.browserslistrc:last 2 chrome versions last 2 firefox versions last 2 safari versions -
@babel/preset-react- Preset for React -
@babel/preset-typescript- Preset for TypeScript
react-refresh/babel- This package implements the wiring necessary to integrate Fast Refresh (HMR) into Babel. Work closely together with@pmmmwh/react-refresh-webpack-plugin(Only in development mode)@babel/plugin-transform-runtime- A plugin that enables the re-use of Babel's injected helper code (replace the direct function insertion into the code with imports from@babel/runtime) to save on codesize.
postcss- is a tool for transforming styles with JS pluginsautoprefixer- PostCSS plugin to parse CSS and add vendor prefixes to CSS rules.If you need more you can replace it withpostcss-preset-envwhich includes autoprefixer
.editorconfig- is helper for maintain consistent coding styles across various editors and IDEs.
prettier- is an code formatter. Also parse some EditorConfig rules
eslint- is a static code analysis tool for identifying problematic patterns.typescript-eslint- allow ESLint to lint TypeScript files.
eslint-config-prettier- Turns off all rules that are unnecessary or might conflict with Prettier
eslint-plugin-import- This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, and prevent issues with misspelling of file paths and import names.eslint-import-resolver-typescript- This resolver plugin adds TypeScript support toeslint-plugin-import
eslint-plugin-react- React specific linting rules for ESLint. I am also extendsreact/jsx-runtimefor support new JSX transform from React 17.eslint-plugin-react-hooks- This ESLint plugin enforces the Rules of Hooks.eslint-plugin-jsx-a11y- Static AST checker for accessibility rules on JSX elements.eslint-plugin-unicorn- Various awesome ESLint rules.
stylelint- is a CSS linter
stylelint-config-standard-scss- Turns on SCSS support & some SCSS rules. By default extendsstylelint-config-standardandstylelint-config-recommended-scss.stylelint-config-standard- Turns on additional rules to enforce the common stylistic conventions found within a handful of CSS styleguides.[!NOTE] Since the
stylelint-config-standard-scsspackage extends thestylelint-config-standardpackage, using both may be redundant and problematic. It could result in having two versions of the same dependency in your project, which can cause issues if you update only one of them. However, it can still be useful to have access to new rules provided by this package. Make sure to pay attention to this in your project.stylelint-config-recess-order- Config that sorts related property declarations by grouping together in the rational order
-
husky- Enable Git hooks, likepre-commit,commit-msgetc -
lint-staged- Run linters on git staged files. Work closely together withhuskypre-commithook. It has its own config, which is located in.lintstagedrc.json -
commitlint- Lint commit messages. Work closely together withhuskycommit-msghook. It has its own config, which is located in.commitlintrc.jsonExpanded by
@commitlint/config-conventional- Shareablecommitlintconfig enforcing conventional commits -
commitizen- is a tool designed to define a standard way of committing rules. It has its own config, which is located in.czrc. You can use it withnpm run cmExpanded by
cz-conventional-changelog- A commitizen propmpts adapter for the Angular version of conventional commits -
Automates the whole package release workflow including: determining the next version number, generating the release notes, and upgrading the package version. It has its own config, which is located in
.releaserc.json- config description. This package is primarily used in a CI environment-
@semantic-release/commit-analyzer- plugin to analyze commits with conventional-changelog. (You do not need to install this plugin. semantic-release comes with this plugin out of the box). Expanded byconventional-changelog-conventionalcommits[!NOTE] Since this is project-specific, I've decided to label the "chore" type as a patch release (
{ "type": "chore", "release": "patch" }), which is typically used for updating packages To allow for the possibility of "chore" breaking releases, add the following rule above ({ "type": "chore", "release": "patch" }) for correct rule applies. If you want to use default preset settings, you could delete this two lines. -
@semantic-release/release-notes-generator- plugin to generate changelog content with conventional-changelog (You do not need to install this plugin. semantic-release comes with this plugin out of the box). Expanded byconventional-changelog-conventionalcommits -
@semantic-release/changelog- plugin to create or update a changelog file -
@semantic-release/npm- plugin to publish a npm package and bump version inpackage.json[!NOTE] Since this project is not a package for publication. This plugin is only needed to update the version in package.json (this is regulated by
private: truein package.json) -
@semantic-release/github- plugin to publish a GitHub release and comment on released Pull Requests/Issues. (You do not need to install this plugin. semantic-release comes with this plugin out of the box) -
@semantic-release/git- plugin to commit release assets \ tag version to the project's git repository
conventional-changelog-conventionalcommits- same preset that used forcommitizen(cz-conventional-changelog) andcommitlint(@commitlint/config-conventional). Since I have overridden the angular preset used by semantic-release by default, it must be declared in direct dependencies.
-
plop- micro-generator framework that makes it easy to create files
Since some Webpack, ESLint plugins or other dev tools like (stylelint-config-recess-order) require Node.js version ≥ 20.19. you need Node.js 20.19 and above to prepare for future changes. Check recommended version in .nvmrc. You also may need Docker, if you want run production build
- Clone or download the repo
- Browse the downloaded directory
- Install dependencies through
npmnpm i
This template includes Sentry integration for error tracking and performance monitoring in production builds. The DSN is now read from environment variables (no hardcoded DSN in the repo). To enable Sentry features, configure the following:
-
Create a Sentry account and project at sentry.io
-
Local step. Create environment configuration file. Rename
.env.exampleto.envin the project root
-
Fill your Sentry configuration values:
SENTRY_AUTH_TOKEN: Create an auth token athttps://sentry.io/orgredirect/organizations/:orgslug/settings/auth-tokens/with "Project: Read & Write" and "Release: Admin" permissionsSENTRY_ORG: Your organization slug (found in your Sentry URL)SENTRY_PROJECT: Your project slug (found in your Sentry project settings)SENTRY_DSN: Project DSN (from Project Settings → Client Keys)
-
Add
.envfile to build pipe, like:"build": "node --env-file=.env ./node_modules/webpack-cli/bin/cli.js --config-node-env production --config config/webpack/webpack.production.js",or pass values directlySENTRY_AUTH_TOKEN=yourtoken SENTRY_ORG=yourorg SENTRY_PROJECT=yourproj SENTRY_DSN=yourdsn npm run build(Unix example)
- Configure GitHub Actions (Optional): If you want Sentry integration to work in your CI/CD pipeline:
- Go to your repository Settings → Secrets and variables → Actions
- Add the following Repository secrets:
SENTRY_AUTH_TOKEN: Your Sentry auth token
- Add the following Repository variables:
SENTRY_ORG: Your organization slugSENTRY_PROJECT: Your project slugSENTRY_DSN: Your Sentry DSN
- The GitHub Deploy Action workflow will use these secret & values during production builds
One-time development build:
npm run devWatcher (will update the build after each change):
npm run watch⭐ Dev Server (provides you with a simple web server and the ability to use HMR):
npm start⭐ One-time production build with Bundle Analazer stats:
npm run buildRun production build inside docker on http://localhost/ (you might need start Docker before run this command):
docker compose up -d --buildFormat & fix the code by ESLint, Prettier, and Stylelint:
npm run formatOnly checks the code for compliance with rules by ESLint, Prettier, and Stylelint:
npm run lintYou can also use a specific formatter
npm run lint:prettier # check for compliance with Prettier rules
# or
npm run lint:stylelint # check for compliance with Stylelint rules
# or
npm run format:eslint # format & fix the code with ESLint rulesCheck out more commands at package.json scripts section.
Debug result ESLint config (output eslint-output-config.json):
npm run debug:eslintDebug result Stylelint config (output stylelint-output-config.json):
npm run debug:stylelintDebug result Prettier config (cli output):
npm run debug:prettierGenerate React component:
npm run generateLocally check your next release:
npm run semantic-release:local-checkIt may be necessary to temporarily remove @semantic-release/github plugin from
.releaserc.json
If you want to get a more relevant check (with sync to your GitHub repository state), you could run this:
GH_TOKEN=<YOUR_TOKEN> npx semantic-release --dry-run --no-ci
Create conventional commit:
npm run cmBecause husky is used in the project, this creates a certain restriction on the naming of scripts, described here.
I personally prefer use this VS Code Extension for creating conventional commits.
- Common -
webpack.config.js - Development -
webpack.development.js - Production -
webpack.production.js
Both environments use webpack.config.js, but each environment has its own features:
| Features | Development | Production |
|---|---|---|
| devtool | ✅ - inline-nosources-cheap-source-map* |
❌ - source-map** |
| devServer | ✅ | ❌ |
| historyApiFallback | ✅ | ❌ |
| stats configuration | ✅ - minimal | ❌ |
| ESLint | ✅ | ❌ |
| TS checks | ✅ | ❌ |
| CSS implementation*** | ✅ - style-loader |
✅ - MiniCssExtractPlugin |
| Proxy backend requests | ✅ - Webpack devServer.proxy |
✅ - NGINX proxy_pass |
| ReactRefreshWebpackPlugin | ✅ | ❌ |
| TerserPlugin | ❌ | ✅ |
| CssMinimizerPlugin | ❌ | ✅ |
| HtmlWebpackPlugin minify | ❌ | ✅ |
| BundleAnalyzerPlugin | ❌ | ✅ |
| SentryWebpackPlugin | ❌ | ✅ |
| CopyWebpackPlugin | ❌ | ✅ |
| Output files name | Default | Contenthash with .bundle/.chunk suffixes |
| Favicon**** | 🤔 | ✅ |
* You can set eval or false options to increase build speed, but in this case, you should manually set sourceMap to true in css-loader, scss-loader, and postcss-loader.
** Source maps are deleted after uploading to the Sentry server, so they are not included in the final bundle
*** mini-css-extract-plugin is more often used in production mode to get separate css files. For development mode (including webpack-dev-server) we use style-loader, because it injects CSS into the DOM using multiple style tags and works faster.
**** In previous commits, I refused to use the clean-webpack-output plugin because I noticed the presence of a native function that appeared in Webpack 5.20+ output.clean. Unfortunately, it has certain problems with the favicon. Therefore, if this bug is not fixed soon, I will return to the previous version (especially since this plugin was updated recently).
HTML - public/index.html
JS/TS - src/
Global CSS - src/styles
Assets - src/assets - all assets that used directly in target code
Fonts -
src/assets/fontsImages/SVG -
src/assets/imagesOther Assets -
src/assets/*
Static files - public/static - files in this folder will be copied to the dist root as is (without any processing) during production builds only. During development, devServer will look at the public/static folder. E.g., robots.txt.
-
SVG import
To import SVG as a React component, use default svg extension:
import SvgComponent from '@assets/images/example.svg' // props => React.createElement("svg",...
to import SVG as an asset (url), add resource query (
?url) to svg extension:in TSX/JSX/JS/TS files:
import svgSrc from '@assets/images/example.svg?url' // data:image/svg+xml;base64,PHN2ZyB4bW...
in CSS/SCSS files:
.svg { background-image: url('@assets/images/example.svg?url'); /* data:image/svg+xml;base64,PHN2ZyB4bW...*/ }
-
I set
useBuiltIns: 'usage'which automatically detects the polyfills needed to be based on the language features used in your source code. This ensures only the minimum amount of polyfills are included in your final bundle. Additionaly i setproposals: true, forObject.groupBy, since not all major browsers currently support it (31.10.2023).presets: [ [ '@babel/preset-env', { useBuiltIns: 'usage', corejs: { version: '3.33', proposals: true }, // The version string can be any supported core-js versions }, ], ]
-
Set these options in
TerserPluginto remove comments from code and preventLICENSE.txtfiles creation.optimization: { minimizer: [ new TerserPlugin({ terserOptions: { format: { comments: false, }, }, extractComments: false, }) ], },
In production mode eg
HTMLWebpackPluginminify your HTML code by defaultI'm decide to remove
contextfield from config, since@pmmmwh/react-refresh-webpack-plugin&fork-ts-checker-webpack-pluginincorrectly infer root directory, while set context tosrcfolder.- Formatting & Linting commands
ESLint & Prettier & Stylelint formatting works separately. So, when you run
npm run format:eslintit will only fix ESLint rules, but not apply Prettier rules formatting. If you want both runnpm run format:eslint && npm run format:prettierornpm run format, which also includes Stylelint formatting.To understand which extensions are used in each command, check out
package.jsonscripts section.- CI
If you wish to make a prerelease, you can begin working in the
alphaorbetabranches.If you need to bypass the git commit hooks, use the
-nor--no-verifyoption. For example:git commit -n -m "message" # or git commit --no-verify -m "message"
If you need to bypass
huskychecks, pass the environment variableHUSKY=0. For example (macOS/Linux):HUSKY=0 git commit -m "message" # or for Windows: cross-env HUSKY=0 git commit -m "message"
If you want to skip
semantic-releasechecks for commit, you could add scope -no-release. For example:git commit -m "chore(no-release): message"If you want to skip
release jobfor commit, you could add[skip ci]text in your commit message. For example:git commit -m "chore: message [skip ci]"If you want ti skip all above:
git commit -n -m "chore(no-release): message [skip ci]"
-
- Add React Hot Reloading support -
react-refresh-webpack-plugin -
- Upgrade
stylelintto15.0.0 -
- Add runtime tsc checks
-
- Add SVG loader
-
- Add
semantic-release -
- Add env webpack plugin
This template is based on the migration of this example to Webpack 5 and also from these sources:
- webpack Boilerplate - Sensible webpack 5 boilerplate using Babel, PostCSS, and Sass with a hot dev server and an optimized production build.
- Webpack 5 Boilerplate Template - Simple starter webpack 5 project template supporting SASS/PostCSS, Babel ES7, browser syncing, code linting. Easy project setup having multiple features and developer-friendly tools.
- Create App - Frontend build config generator