-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwebpack.config.js
173 lines (162 loc) · 6.66 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
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer') //package.json > scripts > stats
//optimization plugins
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
const TerserWebpackPlugin = require('terser-webpack-plugin')
//not all babel presets inserts like plugins
const isDev = process.env.NODE_ENV === 'development' //true if development
const isProd = !isDev
console.log('isDev: ', isDev)
const pathToBundle = path.resolve(__dirname, 'dist')
const pathToIcon = path.resolve(__dirname, 'src', 'assets', 'icons.ico')
const pathToContext = path.resolve(__dirname, 'src')
const optimization = () => {
const config = {
splitChunks: { //when one library is connected to different scripts
chunks: "all" //webpack assembles this library multiple times.
} //This option points webpack assemble all libraries once
}
if (isProd) {
config.minimizer = [
new OptimizeCssAssetsWebpackPlugin(),
new TerserWebpackPlugin()
]
}
return config
}
const plugins = () => {
const base = [ //Webpack assembly extensions
new HtmlWebpackPlugin({ //needs to determine template
// favicon: pathToIcon,
template: "./index.html",
minify: {
collapseWhitespace: isProd
}
}),
new CleanWebpackPlugin(), //deletes all files from bundle
new CopyWebpackPlugin({
patterns: [ //copies files from folders to bundle during assembly
{
from: pathToIcon,
to: pathToBundle
}
]
}),
new MiniCssExtractPlugin({ //Extracts styles to css file in bundle
filename: filename(`css`)
}),
]
if (isProd){ //helps to visualize packages size in html
base.push( new BundleAnalyzerPlugin() )
}
return base
}
const filename = ext => isDev ? `[name].${ext}` : `[name].[hash].${ext}`
const cssLoaders = extra => {
const loaders = [{ //another approach to use loaders
loader: MiniCssExtractPlugin.loader,
options: { //to modify loader options
hmr: isDev, //Hot Module Replacement
reloadAll: true
}
},
'css-loader']
if (extra) {
loaders.push(extra)
}
return loaders
}
const babelPresets = preset => {
const config = {
exclude: path.resolve(__dirname, 'node_modules'), // js files from node_modules will be ignored
use: [] //place for loaders
}
const babelLoaderConfig = { //default babel setup
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env', //default preset
],
plugins: [
'@babel/plugin-proposal-class-properties' //Translate classes to old ECMA
]
}
}
if (preset === 'JavaScript') {
config.test = /\.js$/ //regexp for js files
if (isDev) { //eslint connected in developer mode
config.use.push('eslint-loader')
}
} else if (preset === 'TypeScript') {
config.test = /\.ts$/ //regexp for typeScript files
babelLoaderConfig.options.presets.push('@babel/preset-typescript') //and babel preset for typescript
} else if (preset === 'React') {
config.test = /\.jsx$/ //regexp for jsx(react) files
babelLoaderConfig.options.presets.push('@babel/preset-react') //and babel preset for react/jsx
}
config.use.push(babelLoaderConfig)
return config
}
module.exports = {
context: pathToContext, //shortcut for all paths in config
mode: 'development', // development/production - types of build
entry: { //entry points for scripts
main: ['@babel/polyfill', './index.jsx'], // scriptName : path || array
analytics: './analytics.ts' //not all babel presets inserts like modules
}, //and @babel/polyfill inserts here
output: {
filename: filename(`js`), //mask to output files [hash]/[contenthash]/
// [chunkhash]/[name]/[id]/[query]/[function]
path: pathToBundle //path to output bundle folder
},
resolve: {
extensions: ['.js', '.css', '.jpg', '.json', '.ico'], //this extensions will be parsed in paths to files
alias: {
'@modules': path.resolve(__dirname, 'src', 'modules'), // shortcuts to folders
'@': './src',
'@styles': path.resolve(__dirname, 'src', 'styles'),
'@assets': path.resolve(__dirname, 'src', 'assets')
}
},
optimization: optimization(),
devServer: { //Webpack "online" assembly
port: 4200, //Points to port
hot: isDev // equal to hmr - Hot Module Replacement
},
devtool: isDev ? 'source-map' : '', //isBuild => default https://webpack.js.org/configuration/devtool/
plugins: plugins(),
module: {
rules: [ //needs to process files with different extensions
{
test: /\.css$/, //regexp for styles
use: cssLoaders() //will be processed with two style loaders
//!!! webpack is reading loaders right-to-left !!!
},
{
test: /\.(png|jpg|svg|gif)$/, //images(and another files)
use: ['file-loader'] //will be processed with file loader
},
{
test: /\.ttf$/, //fonts too
use: ['file-loader']
},
//Pre-processors
{
test: /\.less$/, //regexp for less
use: cssLoaders('less-loader')
//!!! webpack is reading loaders right-to-left !!!
},
{
test: /\.s[ca]ss$/, //regexp for sass
use: cssLoaders('sass-loader')
},
babelPresets('JavaScript'),
babelPresets('TypeScript'),
babelPresets('React')
]
}
}