Skip to content

Commit f94384e

Browse files
committed
feat: new configuration for bundling
1 parent ab252bb commit f94384e

File tree

2 files changed

+206
-65
lines changed

2 files changed

+206
-65
lines changed

package.json

+59-49
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
{
22
"name": "webpack-react-typescript-template",
3-
"version": "1.0.0",
4-
"description": "Template for create react app using webpack and typescript",
3+
"version": "2.0.0",
4+
"license": "MIT",
5+
"description": "Modern template to start creating react app using webpack and typescript.",
56
"keywords": [
67
"react",
78
"typescript",
89
"webpack",
910
"react-router",
11+
"styled-components",
1012
"i18next",
1113
"eslint",
1214
"prettier",
1315
"husky",
1416
"commitlint"
1517
],
16-
"author": "Martik Avagyan <martikavagyan1@gmail.com> (https://github.com/m-avagyan)",
18+
"author": "Martik Avagyan <dev@martikavagyan.com> (https://github.com/m-avagyan)",
1719
"homepage": "https://github.com/m-avagyan/webpack-react-typescript-template#readme",
1820
"repository": {
1921
"type": "git",
@@ -23,62 +25,70 @@
2325
"url": "https://github.com/m-avagyan/webpack-react-typescript-template/issues"
2426
},
2527
"scripts": {
26-
"start": "webpack serve --progress --mode development",
27-
"clean": "rm -rf ./build",
28-
"build": "yarn clean && webpack --progress --mode production",
29-
"lint": "yarn eslint src --ext .js,.ts,.tsx --ignore-pattern '!.*.js' --no-error-on-unmatched-pattern",
30-
"lint:fix": "yarn lint --fix"
28+
"clean": "rm -rf ./dist",
29+
"prepare-icons": "node prepare-icons.js",
30+
"build": "webpack --progress --mode production",
31+
"analyze": "webpack --progress --mode production --env analyze",
32+
"dev": "yarn webpack serve --progress --mode none",
33+
"start": "yarn webpack serve --progress --mode development",
34+
"watch": "yarn webpack serve --progress --mode production",
35+
"lint": "eslint src --ext .js,.ts,.tsx --ignore-pattern '!.*.js'",
36+
"format": "yarn lint --fix",
37+
"postinstall": "husky install"
38+
},
39+
"dependencies": {
40+
"i18next": "^21.9.2",
41+
"i18next-browser-languagedetector": "^6.1.5",
42+
"i18next-resources-to-backend": "^1.0.0",
43+
"react": "^18.2.0",
44+
"react-dom": "^18.2.0",
45+
"react-router-dom": "5.3.3",
46+
"styled-components": "^5.3.6"
3147
},
3248
"devDependencies": {
33-
"@babel/core": "^7.19.1",
34-
"@babel/preset-env": "^7.19.1",
49+
"@babel/core": "^7.20.12",
50+
"@babel/preset-env": "^7.20.2",
3551
"@babel/preset-react": "^7.18.6",
3652
"@babel/preset-typescript": "^7.18.6",
37-
"@commitlint/cli": "^17.1.1",
38-
"@commitlint/config-conventional": "^17.1.0",
39-
"@svgr/webpack": "^6.3.1",
40-
"@types/react": "^17.0.1",
41-
"@types/react-dom": "^17.0.1",
42-
"@typescript-eslint/eslint-plugin": "4.0.1",
43-
"@typescript-eslint/parser": "4.0.1",
44-
"babel-loader": "^8.2.5",
45-
"css-loader": "^6.7.1",
46-
"eslint": "^7.26.0",
47-
"eslint-plugin-jsx-a11y": "^6.4.1",
48-
"eslint-plugin-prettier": "^3.4.0",
49-
"eslint-plugin-react": "^7.23.2",
50-
"eslint-plugin-react-hooks": "^4.2.0",
53+
"@commitlint/cli": "^17.4.4",
54+
"@commitlint/config-conventional": "^17.4.4",
55+
"@svgr/webpack": "^6.5.1",
56+
"@trivago/prettier-plugin-sort-imports": "^4.0.0",
57+
"@types/node": "^18.11.18",
58+
"@types/react": "^18.0.27",
59+
"@types/react-dom": "^18.0.10",
60+
"@types/react-i18next": "^8.1.0",
61+
"@types/react-router-dom": "^5.3.3",
62+
"@types/styled-components": "^5.1.26",
63+
"@typescript-eslint/eslint-plugin": "^5.49.0",
64+
"@typescript-eslint/parser": "^5.49.0",
65+
"babel-loader": "^9.1.2",
66+
"babel-plugin-styled-components": "^2.0.7",
67+
"copy-webpack-plugin": "^11.0.0",
68+
"css-loader": "^6.7.3",
69+
"dotenv-webpack": "^8.0.1",
70+
"esbuild-loader": "^2.21.0",
71+
"eslint": "^8.32.0",
72+
"eslint-plugin-jsx-a11y": "^6.7.1",
73+
"eslint-plugin-prettier": "^4.2.1",
74+
"eslint-plugin-react": "^7.32.1",
75+
"eslint-plugin-react-hooks": "^4.6.0",
5176
"file-loader": "^6.2.0",
5277
"html-webpack-plugin": "^5.5.0",
5378
"husky": "^8.0.0",
54-
"lint-staged": "^13.0.3",
55-
"prettier": "^2.3.0",
79+
"mini-css-extract-plugin": "^2.7.2",
80+
"postcss": "^8.4.31",
81+
"postcss-loader": "^7.0.2",
82+
"postcss-preset-env": "^7.8.3",
83+
"prettier": "^2.8.3",
5684
"style-loader": "^3.3.1",
57-
"ts-loader": "^9.4.1",
58-
"typescript": "^4.8.2",
59-
"webpack": "^5.74.0",
60-
"webpack-cli": "^4.10.0",
85+
"ts-loader": "^9.4.2",
86+
"typescript": "^4.9.4",
87+
"webpack": "^5.76.0",
88+
"webpack-bundle-analyzer": "^4.8.0",
89+
"webpack-cli": "^5.0.1",
6190
"webpack-dev-server": "^4.11.1"
6291
},
63-
"dependencies": {
64-
"i18next": "^21.9.2",
65-
"i18next-browser-languagedetector": "^6.1.5",
66-
"i18next-resources-to-backend": "^1.0.0",
67-
"react": "^17.0.1",
68-
"react-dom": "^17.0.1",
69-
"react-i18next": "^11.18.6",
70-
"react-router-dom": "^6.4.1"
71-
},
72-
"lint-staged": {
73-
"*.{js,jsx,ts,tsx}": [
74-
"eslint --quiet --cache --fix"
75-
],
76-
"*.{json,js,ts,jsx,tsx,html}": [
77-
"prettier --write"
78-
]
79-
},
80-
"license": "MIT",
81-
"private": true,
8292
"engines": {
8393
"node": ">=8.0.0",
8494
"npm": ">=6.0.0",

webpack.config.js

+147-16
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,34 @@
11
const path = require('path');
2+
23
const HtmlWebpackPlugin = require('html-webpack-plugin');
4+
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
5+
const Dotenv = require('dotenv-webpack');
6+
const CopyPlugin = require('copy-webpack-plugin');
37

4-
const Modes = {
5-
DEVELOPMENT: 'development',
6-
PRODUCTION: 'production',
7-
};
8+
const { ESBuildMinifyPlugin } = require('esbuild-loader');
9+
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
810

911
module.exports = (env, { mode }) => {
10-
const isProduction = mode === Modes.PRODUCTION;
12+
const isProduction = mode === 'production';
1113

1214
return {
1315
mode,
1416
entry: path.join(__dirname, 'src', 'index.tsx'),
17+
1518
resolve: {
16-
extensions: ['.tsx', '.ts', '.js', '.jsx'],
19+
extensions: ['.ts', '.tsx', '.js', '.jsx'],
20+
alias: {
21+
'@': path.resolve(__dirname, 'src/'),
22+
},
1723
},
24+
1825
output: {
19-
filename: 'bundle.js',
20-
path: path.resolve(__dirname, 'build'),
2126
publicPath: '/',
27+
path: path.resolve(__dirname, 'dist'),
28+
filename: isProduction ? 'js/[name].[chunkhash].js' : 'js/[name].js',
29+
chunkFilename: isProduction ? 'js/[name].[chunkhash].js' : 'js/[name].js',
2230
},
31+
2332
module: {
2433
rules: [
2534
{
@@ -28,32 +37,153 @@ module.exports = (env, { mode }) => {
2837
exclude: /node_modules/,
2938
},
3039
{
31-
test: /\.?js$/,
40+
test: /\.?(js|jsx)$/,
3241
exclude: /node_modules/,
3342
use: {
3443
loader: 'babel-loader',
44+
options: {
45+
presets: ['@babel/preset-env', '@babel/preset-react', '@babel/preset-typescript'],
46+
plugins: [
47+
[
48+
'babel-plugin-styled-components',
49+
{
50+
minify: isProduction,
51+
transpileTemplateLiterals: isProduction,
52+
},
53+
],
54+
],
55+
},
3556
},
3657
},
3758
{
3859
test: /\.css$/i,
39-
use: ['style-loader', 'css-loader'],
60+
use: [
61+
isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
62+
63+
{
64+
loader: 'css-loader',
65+
options: {
66+
importLoaders: 1,
67+
modules: true,
68+
},
69+
},
70+
{
71+
loader: 'postcss-loader',
72+
options: {
73+
postcssOptions: {
74+
plugins: [
75+
[
76+
'postcss-preset-env',
77+
{
78+
autoprefixer: {
79+
grid: true,
80+
flexbox: true,
81+
},
82+
},
83+
],
84+
],
85+
},
86+
},
87+
},
88+
],
4089
},
4190
{
4291
test: /\.(png|jp(e*)g|gif|webp|avif)$/,
43-
use: ['file-loader'],
92+
use: {
93+
loader: 'file-loader',
94+
options: {
95+
name: 'images/[name].[ext]',
96+
},
97+
},
4498
},
4599
{
46100
test: /\.svg$/,
47-
use: ['@svgr/webpack'],
101+
use: [
102+
{
103+
loader: '@svgr/webpack',
104+
options: {
105+
native: false,
106+
},
107+
},
108+
],
48109
},
49110
],
50111
},
112+
51113
plugins: [
52114
new HtmlWebpackPlugin({
53-
template: path.join(__dirname, 'src', 'index.html'),
54-
favicon: path.join(__dirname, 'src', 'assets/images/favicon.ico'),
115+
template: path.join(__dirname, 'public', 'index.html'),
116+
minify: isProduction,
117+
hash: isProduction,
118+
cache: isProduction,
119+
showErrors: !isProduction,
55120
}),
56-
],
121+
122+
new Dotenv({
123+
systemvars: true,
124+
}),
125+
new MiniCssExtractPlugin(),
126+
127+
new CopyPlugin({
128+
patterns: [
129+
{
130+
from: 'public/favicon.ico',
131+
to: '.',
132+
},
133+
{
134+
from: 'public/robots.txt',
135+
to: '.',
136+
},
137+
{
138+
from: 'public/sitemap.xml',
139+
to: '.',
140+
},
141+
{
142+
from: 'public/ads.txt',
143+
to: '.',
144+
},
145+
],
146+
}),
147+
].concat(
148+
!env.analyze
149+
? []
150+
: [
151+
new BundleAnalyzerPlugin({
152+
analyzerHost: 'localhost',
153+
analyzerPort: 3006,
154+
reportTitle: 'Template - Analyze Bundle Sizes',
155+
}),
156+
]
157+
),
158+
159+
optimization: {
160+
minimize: isProduction,
161+
mergeDuplicateChunks: true,
162+
removeEmptyChunks: true,
163+
sideEffects: false,
164+
minimizer: [
165+
new ESBuildMinifyPlugin({
166+
target: 'es2015',
167+
}),
168+
],
169+
splitChunks: {
170+
chunks: 'all',
171+
cacheGroups: {
172+
vendors: {
173+
test: /[\\/]node_modules[\\/]/,
174+
chunks: 'all',
175+
enforce: true,
176+
name: (module) => {
177+
const [, match] = module.context.match(
178+
/[\\/]node_modules[\\/](.*?)([\\/]([^\\/]*)([\\/]([^\\/]*))?([\\/]([^\\/]*))?|$)/
179+
);
180+
181+
return `vendors/${match.replace('@', '')}`;
182+
},
183+
},
184+
},
185+
},
186+
},
57187

58188
performance: {
59189
maxEntrypointSize: Infinity,
@@ -63,8 +193,9 @@ module.exports = (env, { mode }) => {
63193
devtool: isProduction ? 'source-map' : 'inline-source-map',
64194

65195
devServer: {
66-
host: 'localhost',
196+
host: '0.0.0.0',
67197
port: 3000,
198+
server: 'https',
68199
historyApiFallback: true,
69200
},
70201
};

0 commit comments

Comments
 (0)