-
Notifications
You must be signed in to change notification settings - Fork 11
/
webpack.config.js
175 lines (160 loc) · 5.12 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
const fs = require("fs");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const bootstrapPath =
__dirname + "/node_modules/bootstrap-sass/assets/stylesheets";
// A custom node-sass importer that removes some unwanted rules from _normalize.scss.
function importerWhichRewritesBootstrapNormalizeScss(url, prev, done) {
if (url != "bootstrap/normalize") {
done(null);
return;
}
var originalPath = bootstrapPath + "/bootstrap/_normalize.scss";
fs.readFile(originalPath, "utf8", (err, data) => {
if (err) return done(err);
function remove(what) {
if (!data.includes(what)) throw Error(`"${what}" not found`);
data = data.replace(what, "");
}
// Don't use pointer cursor on buttons.
// http://lists.w3.org/Archives/Public/public-css-testsuite/2010Jul/0024.html
remove("cursor: pointer; // 3");
// Don't inherit color and font on inputs and selects.
remove("color: inherit; // 1");
remove("font: inherit; // 2");
done({ contents: data });
});
}
const outputPath = __dirname + "/votrfront/static";
// A plugin which writes the current status to votrfront/static/status.
// - "busy" during compilation
// - "failed" on errors
// - "ok_dev" or "ok_prod" on success
// votrfront/front.py reads the status to check if it can serve the page.
function StatusFilePlugin(mode) {
this.apply = function (compiler) {
function writeStatus(content, callback) {
fs.mkdir(outputPath, function (err) {
if (err && err.code != "EEXIST") return callback(err);
fs.writeFile(outputPath + "/status", content + "\n", "utf8", callback);
});
}
function handleRunEvent(compilationParams, callback) {
writeStatus("busy", callback);
}
compiler.hooks.run.tapAsync("StatusFilePlugin", handleRunEvent);
compiler.hooks.watchRun.tapAsync("StatusFilePlugin", handleRunEvent);
compiler.hooks.done.tapAsync("StatusFilePlugin", (stats, callback) => {
const status = stats.compilation.errors.length ? "failed" : "ok_" + mode;
writeStatus(status, callback);
});
};
}
// A plugin which deletes old .map files. We can't use clean-webpack-plugin to
// delete *.map before every compilation, because in watch mode, if a .js file
// doesn't change then its .map file won't be regenerated.
function CleanMapFilesPlugin() {
this.apply = function (compiler) {
compiler.hooks.afterEmit.tapAsync(
"CleanMapFilesPlugin",
function (compilation, callback) {
for (const file of fs.readdirSync(outputPath)) {
if (
file.match(/\.map$/) &&
!compilation.assets[file] &&
compilation.assets[file.replace(/\.\w+\.map$/, "")]
) {
fs.unlinkSync(outputPath + "/" + file);
}
}
callback();
}
);
};
}
function makeConfig(mode) {
const config = {
output: {
path: outputPath,
filename: mode == "development" ? "[name].dev.js" : "[name].min.js",
sourceMapFilename: "[file].[contenthash].map", // it seems Chrome caches source maps even if "Disable cache" is enabled
},
plugins: [
new MiniCssExtractPlugin({ filename: "style.css" }),
new StatusFilePlugin(mode == "development" ? "dev" : "prod"),
new CleanMapFilesPlugin(),
],
resolve: {
extensions: [".ts", ".tsx", ".js"],
},
module: {
rules: [
{
// Without this, webpack tries to replace `define.amd` in jquery and
// file-saver with its own definition.
parser: { amd: false },
},
{
test: /\.[tj]sx?$/,
exclude: /node_modules/,
loader: "ts-loader",
},
{
test: /node_modules\/bootstrap-sass\//,
loader: "imports-loader",
options: { imports: ["default jquery jQuery"] },
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "sass-loader",
options: {
sassOptions: {
includePaths: [bootstrapPath],
outputStyle: mode == "development" ? undefined : "compressed",
importer: importerWhichRewritesBootstrapNormalizeScss,
},
},
},
],
},
{
test: /\.svg$/,
type: "asset/inline",
},
],
},
optimization: {
splitChunks: {
chunks: "all",
minSize: 0,
name: (module, chunks, cacheGroupKey) => {
if (cacheGroupKey !== "defaultVendors") throw Error("wat");
if (chunks.length !== 1) throw Error("wat");
return `vendors_${chunks[0].name}`;
},
},
},
devtool: "source-map",
performance: {
maxAssetSize: 750 * 1024,
maxEntrypointSize: 750 * 1024,
},
};
return config;
}
module.exports = function (env, args) {
return [
{
...makeConfig(args.mode),
entry: { votr: "./votrfront/js/main" },
},
{
...makeConfig(args.mode),
entry: { prologue: "./votrfront/js/prologue" },
target: ["web", "es5"],
},
];
};