-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
webpack.config.js
194 lines (189 loc) · 6.45 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
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
const Critters = require('critters-webpack-plugin');
const SizePlugin = require('size-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const WorkboxPlugin = require('workbox-webpack-plugin');
const ForkTsCheckerNotifierWebpackPlugin = require('fork-ts-checker-notifier-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const cssnano = require('cssnano');
// Utils
const removeEmpty = items => items.filter(i => i !== null && i !== undefined);
const propIf = (envVal, value, alt) => (envVal ? value : alt);
const propIfNot = (envVal, value, alt) => (!envVal ? value : alt);
const makeIfProp = envValue => (value, alt) =>
isUndefined(value) ? envValue : propIf(envValue, value, alt);
const makeIfNotProp = envValue => (value, alt) =>
isUndefined(value) ? !envValue : propIfNot(envValue, value, alt);
// Env setup
const isProduction = process.env.NODE_ENV == 'production';
const ifProduction = makeIfProp(isProduction);
const ifNotProduction = makeIfNotProp(isProduction);
// webpack.config.js
module.exports = {
context: process.cwd(),
mode: ifProduction('production', 'development'),
entry: {
main: ifProduction(['./src/index-prod.ts'], ['./src/index-dev.ts']),
},
output: {
path: __dirname + '/dist',
chunkFilename: '[name]-[contenthash].js',
filename: ifProduction('[name]-[contenthash].js', '[name].js'),
publicPath: '/',
},
plugins: removeEmpty([
// Place things in template
new HtmlWebpackPlugin({
template: 'index.html',
}),
// Adjust scripts in template
new ScriptExtHtmlWebpackPlugin({
preload: ['main'],
chunks: 'initial',
}),
ifNotProduction(new ForkTsCheckerWebpackPlugin()),
new ForkTsCheckerNotifierWebpackPlugin({
title: 'Typescript',
excludeWarnings: false,
}),
new OptimizeCssAssetsPlugin({
cssProcessor: cssnano,
cssProcessorPluginOptions: {
// The mergeLonghand option is unsafe if we rely on the cascade for env() fallbacks,
// such as safe area insets for iPhone X
// @see https://github.com/cssnano/cssnano/issues/803
preset: ['default', {mergeLonghand: false}],
},
canPrint: false,
}),
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: ifNotProduction('[name].css', '[name]-[contenthash].css'),
chunkFilename: ifNotProduction('[id].css', '[id]-[hash].css'),
}),
new webpack.DefinePlugin({
NOW_GITHUB_COMMIT_SHA: JSON.stringify(
(process.env.NOW_GITHUB_COMMIT_SHA || 'local').slice(0, 7)
),
}),
// Inline critical css, preload fonts
ifProduction(
new Critters({
// Do not removed inlined selectors from source
// This is done because the feature is buggy and removes media queries :/
pruneSource: false,
// Outputs: <link rel="preload" onload="this.rel='stylesheet'"> and LoadCSS fallback
// NOTE: Actually, only does the latter, maybe a PR opportunity/
preload: 'js',
// Inline critical font-face rules, and preload the font URLs
inlineFonts: true,
// preloadFonts: false
// fonts: true
})
),
ifProduction(
new WorkboxPlugin.InjectManifest({
swSrc: './src/sw.js',
importWorkboxFrom: 'local',
})
),
// Track bundle size
ifProduction(new SizePlugin()),
]),
module: {
rules: [
{
test: /\.elm$/,
exclude: [/elm-stuff/, /node_modules/],
use: ifProduction(
[{loader: 'elm-webpack-loader'}],
[
{loader: 'elm-hot-webpack-loader'},
{
loader: 'elm-webpack-loader',
options: {
// add Elm's debug overlay to output
debug: true,
forceWatch: true,
cwd: __dirname,
},
},
]
),
},
{
test: /.tsx?$/,
use: [
{
loader: 'ts-loader',
options: {transpileOnly: ifProduction(false, true)},
},
],
},
{
test: /\.css$/,
use: [
// Load into <style> in dev, or <link href> in production
ifNotProduction(
{loader: 'style-loader'},
{
loader: MiniCssExtractPlugin.loader,
}
),
// CSS -> Webpack's Representation of the world
{loader: 'css-loader', options: {importLoaders: 1}},
// CSS -> Postprocessed CSS
'postcss-loader',
],
// Exclude leaflet.css; we include only a reference to it
exclude: /leaflet\.css/,
},
{
test: /.css$/,
use: [
// Use postcss to bundle leaflet css, while keeping it out of webpack
// This is because we want to reference the leaflet css style inside of the web component
// whereas webpack (css-loader + extractText) assumes top-level styles.
// With top-level styles, we would need to use a <link>. We could do that with file-loader,
// but it leads to a flash of unstyled text. So we must either inline the <style> or use the constructable stylesheets API.
// Either of thos need the text content of the styles, and thus here we are!
{loader: 'postcss-loader'},
],
// Include a reference to leaflet.css, hashed, but do not touch it otherwise
include: /leaflet\.css/,
},
// Load references to file URLs after resolution
// Used, for example, to link urls
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name]-[hash:20].[ext]',
outputPath: 'assets/images',
publicPath: 'assets/images',
},
},
],
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js', '.elm', '.css'],
},
devServer: {
compress: true,
// E.g. /404 should serve index.html, and let Elm handle the route
historyApiFallback: true,
hot: true,
stats: 'errors-only',
},
};
function isUndefined(val) {
return typeof val === 'undefined';
}