2019-08-30 19:16:28 +02:00
|
|
|
import { basename, resolve } from 'path';
|
2019-10-30 20:13:53 +01:00
|
|
|
import { cacheLoader, getExposeLoaders } from './webpack-helpers';
|
2019-10-22 02:57:27 +02:00
|
|
|
import BundleTracker from 'webpack4-bundle-tracker';
|
2019-10-30 20:13:53 +01:00
|
|
|
import CleanCss from 'clean-css';
|
|
|
|
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
2019-10-12 03:37:06 +02:00
|
|
|
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
|
|
|
import OptimizeCssAssetsPlugin from 'optimize-css-assets-webpack-plugin';
|
|
|
|
import TerserPlugin from 'terser-webpack-plugin';
|
2019-10-30 20:13:53 +01:00
|
|
|
// The devServer member of webpack.Configuration is managed by the
|
|
|
|
// webpack-dev-server package. We are only importing the type here.
|
|
|
|
import _webpackDevServer from 'webpack-dev-server';
|
|
|
|
import webpack from 'webpack';
|
2017-05-22 22:49:20 +02:00
|
|
|
|
2019-11-04 23:37:12 +01:00
|
|
|
const assets: { [name: string]: string[] } = require('./webpack.assets.json');
|
2017-07-28 22:53:37 +02:00
|
|
|
|
2019-06-29 10:13:08 +02:00
|
|
|
export default (env?: string): webpack.Configuration[] => {
|
2017-07-28 23:13:58 +02:00
|
|
|
const production: boolean = env === "production";
|
2019-07-18 06:47:06 +02:00
|
|
|
const publicPath = production ? '/static/webpack-bundles/' : '/webpack/';
|
2019-03-24 11:54:17 +01:00
|
|
|
const config: webpack.Configuration = {
|
2019-08-16 05:30:53 +02:00
|
|
|
name: "frontend",
|
2018-04-17 21:59:17 +02:00
|
|
|
mode: production ? "production" : "development",
|
2017-07-28 23:13:58 +02:00
|
|
|
context: resolve(__dirname, "../"),
|
2017-07-28 22:33:40 +02:00
|
|
|
entry: assets,
|
|
|
|
module: {
|
|
|
|
rules: [
|
2019-07-18 06:47:06 +02:00
|
|
|
// Generate webfont
|
|
|
|
{
|
|
|
|
test: /\.font\.js$/,
|
|
|
|
use: [
|
|
|
|
MiniCssExtractPlugin.loader,
|
|
|
|
'css-loader',
|
|
|
|
{
|
|
|
|
loader: 'webfonts-loader',
|
|
|
|
options: {
|
|
|
|
fileName: production ? 'files/[fontname].[chunkhash].[ext]' : 'files/[fontname].[ext]',
|
|
|
|
publicPath,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
2019-07-10 00:05:46 +02:00
|
|
|
// Transpile .js and .ts files with Babel
|
2017-07-28 22:33:40 +02:00
|
|
|
{
|
2019-07-10 00:05:46 +02:00
|
|
|
test: /\.(js|ts)$/,
|
2019-10-04 23:08:11 +02:00
|
|
|
include: [
|
|
|
|
resolve(__dirname, '../static/shared/js'),
|
|
|
|
resolve(__dirname, '../static/js'),
|
|
|
|
],
|
2019-07-10 00:05:46 +02:00
|
|
|
loader: 'babel-loader',
|
2017-07-28 22:33:40 +02:00
|
|
|
},
|
|
|
|
// Uses script-loader on minified files so we don't change global variables in them.
|
|
|
|
// Also has the effect of making processing these files fast
|
2017-08-06 03:53:44 +02:00
|
|
|
// Currently the source maps don't work with these so use unminified files
|
|
|
|
// if debugging is required.
|
2017-07-28 22:33:40 +02:00
|
|
|
{
|
2018-05-28 08:09:49 +02:00
|
|
|
// We dont want to match admin.js
|
|
|
|
test: /(\.min|min\.|zxcvbn)\.js/,
|
2019-06-04 21:11:31 +02:00
|
|
|
use: [cacheLoader, 'script-loader'],
|
2017-07-28 22:33:40 +02:00
|
|
|
},
|
2018-04-25 22:09:48 +02:00
|
|
|
// regular css files
|
|
|
|
{
|
|
|
|
test: /\.css$/,
|
2019-06-06 11:01:44 +02:00
|
|
|
use: [
|
|
|
|
{
|
|
|
|
loader: MiniCssExtractPlugin.loader,
|
|
|
|
options: {
|
|
|
|
hmr: !production,
|
|
|
|
},
|
|
|
|
},
|
2019-06-04 21:11:31 +02:00
|
|
|
cacheLoader,
|
2018-04-25 22:09:48 +02:00
|
|
|
{
|
|
|
|
loader: 'css-loader',
|
|
|
|
options: {
|
2019-03-24 11:54:17 +01:00
|
|
|
sourceMap: true,
|
2018-05-28 08:09:49 +02:00
|
|
|
},
|
2018-04-25 22:09:48 +02:00
|
|
|
},
|
2019-06-06 11:01:44 +02:00
|
|
|
],
|
2018-04-25 22:09:48 +02:00
|
|
|
},
|
2019-08-27 01:23:48 +02:00
|
|
|
// scss loader
|
2018-04-25 22:09:48 +02:00
|
|
|
{
|
2019-08-27 01:23:48 +02:00
|
|
|
test: /\.scss$/,
|
|
|
|
include: resolve(__dirname, '../static/styles'),
|
2019-06-06 11:01:44 +02:00
|
|
|
use: [
|
|
|
|
{
|
|
|
|
loader: MiniCssExtractPlugin.loader,
|
|
|
|
options: {
|
|
|
|
hmr: !production,
|
|
|
|
},
|
|
|
|
},
|
2019-06-04 21:11:31 +02:00
|
|
|
cacheLoader,
|
2018-04-25 22:09:48 +02:00
|
|
|
{
|
|
|
|
loader: 'css-loader',
|
|
|
|
options: {
|
2019-08-27 01:23:48 +02:00
|
|
|
importLoaders: 1,
|
2019-03-24 11:54:17 +01:00
|
|
|
sourceMap: true,
|
|
|
|
},
|
2018-04-25 22:09:48 +02:00
|
|
|
},
|
|
|
|
{
|
2019-08-27 01:23:48 +02:00
|
|
|
loader: 'postcss-loader',
|
2018-04-25 22:09:48 +02:00
|
|
|
options: {
|
2019-03-24 11:54:17 +01:00
|
|
|
sourceMap: true,
|
|
|
|
},
|
|
|
|
},
|
2019-06-06 11:01:44 +02:00
|
|
|
],
|
2018-04-25 22:09:48 +02:00
|
|
|
},
|
2019-06-25 11:39:03 +02:00
|
|
|
{
|
2019-07-12 00:52:56 +02:00
|
|
|
test: /\.hbs$/,
|
2019-06-25 11:39:03 +02:00
|
|
|
loader: 'handlebars-loader',
|
|
|
|
options: {
|
|
|
|
// Tell webpack not to explicitly require these.
|
|
|
|
knownHelpers: ['if', 'unless', 'each', 'with',
|
|
|
|
// The ones below are defined in static/js/templates.js
|
2019-07-17 00:09:48 +02:00
|
|
|
'plural', 'eq', 'and', 'or', 'not',
|
2019-06-25 11:39:03 +02:00
|
|
|
't', 'tr'],
|
2019-07-16 23:20:23 +02:00
|
|
|
preventIndent: true,
|
2019-06-25 11:39:03 +02:00
|
|
|
},
|
|
|
|
},
|
2018-04-25 22:09:48 +02:00
|
|
|
// load fonts and files
|
|
|
|
{
|
2019-07-03 02:22:28 +02:00
|
|
|
test: /\.(woff(2)?|ttf|eot|svg|otf|png)$/,
|
2018-04-25 22:09:48 +02:00
|
|
|
use: [{
|
|
|
|
loader: 'file-loader',
|
|
|
|
options: {
|
2019-07-03 02:22:28 +02:00
|
|
|
name: production ? '[name].[hash].[ext]' : '[name].[ext]',
|
2019-03-24 11:54:17 +01:00
|
|
|
outputPath: 'files/',
|
|
|
|
},
|
|
|
|
}],
|
|
|
|
},
|
2017-07-28 22:33:40 +02:00
|
|
|
],
|
|
|
|
},
|
|
|
|
output: {
|
2017-07-28 23:13:58 +02:00
|
|
|
path: resolve(__dirname, '../static/webpack-bundles'),
|
2019-07-18 06:47:06 +02:00
|
|
|
publicPath,
|
2019-10-22 02:14:28 +02:00
|
|
|
filename: production ? '[name].[contenthash].js' : '[name].js',
|
|
|
|
chunkFilename: production ? '[contenthash].js' : '[id].js',
|
2017-07-28 22:33:40 +02:00
|
|
|
},
|
|
|
|
resolve: {
|
2019-06-21 02:01:59 +02:00
|
|
|
extensions: [".ts", ".js"],
|
2017-07-28 22:33:40 +02:00
|
|
|
},
|
2018-05-22 01:50:25 +02:00
|
|
|
// We prefer cheap-module-source-map over any eval-** options
|
|
|
|
// because the eval-options currently don't support being
|
|
|
|
// source mapped in error stack traces
|
|
|
|
// We prefer it over eval since eval has trouble setting
|
|
|
|
// breakpoints in chrome.
|
|
|
|
devtool: production ? 'source-map' : 'cheap-module-source-map',
|
2019-08-30 19:16:28 +02:00
|
|
|
optimization: {
|
|
|
|
minimizer: [
|
|
|
|
// Based on a comment in NMFR/optimize-css-assets-webpack-plugin#10.
|
|
|
|
// Can be simplified when NMFR/optimize-css-assets-webpack-plugin#87
|
|
|
|
// is fixed.
|
|
|
|
new OptimizeCssAssetsPlugin({
|
|
|
|
cssProcessor: {
|
2019-11-04 23:37:12 +01:00
|
|
|
async process(css, options: any) {
|
2019-08-30 19:16:28 +02:00
|
|
|
const filename = basename(options.to);
|
|
|
|
const result = await new CleanCss(options).minify({
|
|
|
|
[filename]: {
|
|
|
|
styles: css,
|
|
|
|
sourceMap: options.map.prev,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
for (const warning of result.warnings) {
|
|
|
|
console.warn(warning);
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
css: result.styles + `\n/*# sourceMappingURL=${filename}.map */`,
|
|
|
|
map: result.sourceMap,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
},
|
|
|
|
cssProcessorOptions: {
|
|
|
|
map: {},
|
|
|
|
returnPromise: true,
|
|
|
|
sourceMap: true,
|
|
|
|
sourceMapInlineSources: true,
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
new TerserPlugin({
|
|
|
|
cache: true,
|
|
|
|
parallel: true,
|
|
|
|
sourceMap: true,
|
|
|
|
}),
|
|
|
|
],
|
2019-10-22 02:14:28 +02:00
|
|
|
splitChunks: {
|
|
|
|
chunks: "all",
|
|
|
|
// webpack/examples/many-pages suggests 20 requests for HTTP/2
|
|
|
|
maxAsyncRequests: 20,
|
|
|
|
maxInitialRequests: 20,
|
|
|
|
},
|
2019-08-30 19:16:28 +02:00
|
|
|
},
|
2019-10-22 01:26:30 +02:00
|
|
|
plugins: [
|
|
|
|
new BundleTracker({
|
|
|
|
filename: production
|
|
|
|
? 'webpack-stats-production.json'
|
|
|
|
: 'var/webpack-stats-dev.json',
|
|
|
|
}),
|
|
|
|
...production
|
|
|
|
? []
|
|
|
|
: [
|
|
|
|
// Better logging from console for hot reload
|
|
|
|
new webpack.NamedModulesPlugin(),
|
|
|
|
// script-loader should load sourceURL in dev
|
|
|
|
new webpack.LoaderOptionsPlugin({debug: true}),
|
|
|
|
],
|
|
|
|
// Extract CSS from files
|
|
|
|
new MiniCssExtractPlugin({
|
2019-10-22 02:02:14 +02:00
|
|
|
filename: production ? "[name].[contenthash].css" : "[name].css",
|
2019-10-22 02:14:28 +02:00
|
|
|
chunkFilename: production ? "[contenthash].css" : "[id].css",
|
2019-10-22 01:26:30 +02:00
|
|
|
}),
|
2019-10-22 02:02:14 +02:00
|
|
|
new HtmlWebpackPlugin({
|
|
|
|
filename: "5xx.html",
|
|
|
|
template: "static/html/5xx.html",
|
|
|
|
chunks: ["error-styles"],
|
|
|
|
}),
|
2019-10-22 01:26:30 +02:00
|
|
|
],
|
2017-07-28 22:33:40 +02:00
|
|
|
};
|
2018-05-28 08:09:49 +02:00
|
|
|
|
|
|
|
// Expose Global variables for third party libraries to webpack modules
|
|
|
|
// Use the unminified versions of jquery and underscore so that
|
|
|
|
// Good error messages show up in production and development in the source maps
|
2019-11-02 00:06:25 +01:00
|
|
|
const exposeOptions = [
|
2019-06-21 03:16:48 +02:00
|
|
|
{ path: "blueimp-md5/js/md5.js" },
|
|
|
|
{ path: "clipboard/dist/clipboard.js", name: "ClipboardJS" },
|
|
|
|
{ path: "xdate/src/xdate.js", name: "XDate" },
|
2018-05-28 08:09:49 +02:00
|
|
|
{ path: "../static/third/marked/lib/marked.js" },
|
|
|
|
{ path: "../static/generated/emoji/emoji_codes.js" },
|
|
|
|
{ path: "../static/generated/pygments_data.js" },
|
|
|
|
{ path: "../static/js/debug.js" },
|
|
|
|
{ path: "../static/js/blueslip.js" },
|
|
|
|
{ path: "../static/js/common.js" },
|
2019-06-21 03:16:48 +02:00
|
|
|
{ path: "jquery/dist/jquery.js", name: ['$', 'jQuery'] },
|
|
|
|
{ path: "underscore/underscore.js", name: '_' },
|
2019-06-25 11:39:03 +02:00
|
|
|
{ path: "handlebars/dist/cjs/handlebars.runtime.js", name: 'Handlebars' },
|
2019-06-21 03:16:48 +02:00
|
|
|
{ path: "sortablejs/Sortable.js"},
|
|
|
|
{ path: "winchan/winchan.js", name: 'WinChan'},
|
2018-05-28 08:09:49 +02:00
|
|
|
];
|
2019-07-10 00:05:46 +02:00
|
|
|
config.module.rules.unshift(...getExposeLoaders(exposeOptions));
|
2018-05-28 08:09:49 +02:00
|
|
|
|
2019-10-22 01:26:30 +02:00
|
|
|
if (!production) {
|
2017-07-28 22:53:37 +02:00
|
|
|
// Out JS debugging tools
|
2019-10-23 07:46:34 +02:00
|
|
|
for (const name of Object.keys(config.entry)) {
|
2019-11-04 23:37:12 +01:00
|
|
|
assets[name].push('./static/js/debug.js');
|
2019-10-23 07:46:34 +02:00
|
|
|
}
|
2017-07-28 22:53:37 +02:00
|
|
|
config.devServer = {
|
2018-04-25 21:16:08 +02:00
|
|
|
clientLogLevel: "error",
|
|
|
|
stats: "errors-only",
|
2017-07-28 22:53:37 +02:00
|
|
|
};
|
|
|
|
}
|
2019-06-29 10:13:08 +02:00
|
|
|
|
|
|
|
const serverConfig: webpack.Configuration = {
|
|
|
|
mode: production ? "production" : "development",
|
|
|
|
target: "node",
|
|
|
|
context: resolve(__dirname, "../"),
|
|
|
|
entry: {
|
|
|
|
"katex-cli": "shebang-loader!katex/cli",
|
|
|
|
},
|
|
|
|
output: {
|
|
|
|
path: resolve(__dirname, "../static/webpack-bundles"),
|
|
|
|
filename: "[name].js",
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
return [config, serverConfig];
|
2015-10-26 17:11:44 +01:00
|
|
|
};
|