-
Notifications
You must be signed in to change notification settings - Fork 0
/
webpack.config.js
368 lines (315 loc) · 11.1 KB
/
webpack.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
const path = require("path");
const webpack = require("webpack");
const dotenv = require("dotenv");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanObsoleteChunks = require("webpack-clean-obsolete-chunks");
const TerserPlugin = require("terser-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const isProd = process.env.NODE_ENV !== "production";
dotenv.config();
module.exports = {
name: "React Webpack",
mode: process.env.NODE_ENV === "production" ? "production" : "development",
target: "web",
entry: {
bundle: path.resolve(__dirname, "./src/index.js"),
},
devtool: isProd ? "eval-cheap-module-source-map" : "source-map",
resolve: {
modules: ["node_modules", path.resolve(__dirname, "src")],
alias: {
process: "process/browser",
},
extensions: [".js", ".jsx", ".json", ".ts", ".tsx", ".scss"],
fallback: {
fs: false,
path: require.resolve("path-browserify"),
},
},
output: {
path: path.resolve(__dirname, "build"),
publicPath: "/",
pathinfo: true,
filename: process.env.NODE_ENV === "production" ? "[name].[chunkhash].js" : "[name].[fullhash].js",
chunkFilename: process.env.NODE_ENV === "production" ? "chunk.[name].[chunkhash].js" : "chunk.[name].[fullhash].js",
libraryTarget: "umd",
clean: true, // Clean the output directory before emit.
assetModuleFilename: "[name][ext]",
sourceMapFilename: "[name].js.map",
},
devServer: {
headers: {
"access-control-allow-origin": "*",
"Access-Control-Allow-Credentials": true,
"cache-control": "private, max-age=31536000",
},
server: "http",
allowedHosts: "auto",
client: {
progress: true,
reconnect: true,
},
port: 3000,
historyApiFallback: true,
static: {
directory: path.join(__dirname, "public"),
publicPath: ["/"],
serveIndex: true,
},
compress: true,
hot: true,
host: "localhost",
proxy: {
"/api": "http://localhost:5000", // Backend server host on this url
},
},
module: {
strictExportPresence: true,
rules: [
{
test: /\.m?js$/,
type: "javascript/auto",
},
// npm i babel-plugin-styled-components --legacy-peer-deps
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
cacheDirectory: true,
cacheCompression: false,
presets: ["@babel/preset-env"],
plugins: ["@babel/plugin-proposal-class-properties", "babel-plugin-styled-components"],
},
},
},
{
test: /\.js$/,
exclude: [/node_modules/, require.resolve("./public/index.html")],
use: {
loader: "babel-loader",
options: {
cacheDirectory: true,
cacheCompression: false,
presets: [require.resolve("@babel/preset-env")],
plugins: ["@babel/plugin-proposal-class-properties", require.resolve("babel-plugin-styled-components")],
},
},
},
{
test: /\.html$/,
exclude: [/node_modules/, require.resolve("./public/index.html")],
use: [
{
loader: "html-loader",
options: { minimize: !isProd },
},
],
},
// Image Loader
// npm install -D url-loader
// Webpack can also be used to load static resources such as images, videos, and other binary files.
// The most generic way of handling such types of files is by using file-loader or url-loader, which will provide a URL reference for the required resources to its consumers.
// In this section, we will add url-loader to handle common image formats. What sets url-loader apart from file-loader is that if the size of the original file is smaller
// than a given threshold, it will embed the entire file in the URL as base64-encoded contents, thus removing the need for an additional request.
{
test: /\.(png|svg|jpg|gif)$/i,
use: [
{
loader: "file-loader",
options: {
limit: 8192,
name: "[path][name].[hash:8].[ext]",
},
},
],
},
// Below: npm i image-webpack-loader
{
test: /\.(gif|png|jpe?g|svg)$/i,
use: [
"file-loader",
{
loader: "image-webpack-loader",
options: {
mozjpeg: {
progressive: true,
},
// optipng.enabled: false will disable optipng
optipng: {
enabled: false,
},
pngquant: {
quality: [0.65, 0.9],
speed: 4,
},
gifsicle: {
interlaced: false,
},
// the webp option will enable WEBP
webp: {
quality: 75,
},
},
},
],
},
// css-loader: Parses CSS files, resolving external resources, such as images, fonts, and additional style imports.
// style-loader: During development, injects loaded styles into the document at runtime.
// npm install -D css-loader style-loader
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: [["@babel/preset-env", { targets: "defaults" }]],
plugins: ["@babel/plugin-proposal-class-properties"],
customize: require.resolve("babel-preset-react-app/webpack-overrides"),
},
},
},
{
test: /\.handlebars/,
use: "handlebars-loader",
exclude: /node_modules/,
},
// For Scss files
{
test: /\.(sass|scss)$/,
use: [
"style-loader",
"css-loader",
"postcss-loader",
{
loader: "sass-loader",
options: {
implementation: require("sass"),
},
},
{ loader: "postcss-loader", options: { sourceMap: true } },
{ loader: "sass-loader", options: { sourceMap: true, implementation: require("sass") } },
],
},
// File-loader
// When we need to reference any other kinds of files, the generic file-loader will do the job. It works similarly to url-loader,
// providing an asset URL to the code that requires it, but it makes no attempt to optimize it.
// npm install -D file-loader
{
test: /\.(eot|otf|ttf|woff|woff2)$/,
loader: require.resolve("file-loader"),
options: {
name: "[path][name].[hash:8].[ext]",
},
},
// {
// test: /\.(sass|scss|css)$/,
// use: [
// "style-loader",
// {loader: "css-loader",options: { sourceMap: true, importLoaders: 1, modules: false }},
// { loader: "postcss-loader", options: { sourceMap: true } },
// { loader: "sass-loader", options: { sourceMap: true, implementation: require('sass') } },
// ],
// },
],
},
plugins: [
new CleanObsoleteChunks({
verbose: true,
deep: true,
}),
// The generated public/index.html file will load our bundle and bootstrap our application.
new HtmlWebpackPlugin({
template: path.resolve("./public/index.html"),
filename: "./index.html",
favicon: "./public/favicon.ico",
manifest: "./public/manifest.json",
minify: {
removeComments: true,
removeAttributeQuotes: true,
collapseWhitespace: true,
collapseBooleanAttributes: true,
},
inject: true,
hash: true,
title: "development",
}),
new CleanWebpackPlugin({
root: process.cwd(),
verbose: true,
dry: false,
cleanOnceBeforeBuildPatterns: ["**/*", "!stats.json", "!important.js", "!folder/**/*"],
}),
// mini-css-extract-plugin: Extracts loaded styles into separate files for production use to take advantage of browser caching.
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css",
}),
new webpack.ProvidePlugin({
process: "process/browser",
}),
new webpack.DefinePlugin({
"process.env": JSON.stringify(process.env),
}),
new webpack.HotModuleReplacementPlugin(),
],
optimization: {
minimize: true,
runtimeChunk: true,
splitChunks: false,
// splitChunks: {
// chunks: "all",
// minSize: 10000,
// maxSize: 250000,
// },
removeAvailableModules: true,
removeEmptyChunks: true,
mergeDuplicateChunks: true,
minimizer: [new TerserPlugin({ parallel: true, test: /\.js(\?.*)?$/i, terserOptions: { compress: false, mangle: true, output: { comments: false, ascii_only: true } } })],
flagIncludedChunks: true,
usedExports: true,
sideEffects: true,
},
performance: false,
// Configuring External Webpack Dependencies
// If we want to include modules from externally hosted scripts, we need to define them in the configuration. Otherwise, Webpack cannot generate the final bundle.
// We can configure external scripts by using the Webpack externals configuration option. For example, we can use a library from a CDN via a separate <script> tag,
// while still explicitly declaring it as a module dependency in our project.
// externals: {
// react: 'React',
// 'react-dom': 'ReactDOM'
// }
};
// Whenever babel core issue comes up.
// "dependencies": {
// "@babel/core": "^7.4.5",
// "core-js": "^2.6.5",
// },
// npm uninstall core-js, delete your node_modules. Then run npm install and npm install core-js
// cross-env : Run scripts that set and use environment variables across platforms.
/**
* What is Long term caching?
Long-term caching is the process of telling the browser to cache a file for a long time, like 3 months or even 1 year. This is an important setting to ensure that returning users won’t need to download the same JS/CSS files over and over again.
What is Content hashing?
Generate a hash based on the content of the file. This will ensure that, unless we change our base components, the user won’t need to re-download it.
How content hash improve performance ?
The browser won’t download when there is no change in the hash, so below are some example where you can do content hash.
1.npm modules
2.asset files that won’t change
3.Core components
4.common component
5.common modules
we can do a code split for the above scenarios, so that react will create different bundles and webpack will create the content hash.
Example :
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
*/