optimize webpack config for faster build website
- switch to modern html-bundler-webpack-plugin - replace deprecated `file-loader` and `url-loader` with Webpack 5 assets module - create single webpack config instead of two configs
This commit is contained in:
parent
3732d59249
commit
818f752714
12 changed files with 1731 additions and 1293 deletions
|
|
@ -111,17 +111,14 @@
|
||||||
"eslint-plugin-optimize-regex": "1.2.1",
|
"eslint-plugin-optimize-regex": "1.2.1",
|
||||||
"eslint-plugin-promise": "6.1.1",
|
"eslint-plugin-promise": "6.1.1",
|
||||||
"eslint-plugin-sonarjs": "0.20.0",
|
"eslint-plugin-sonarjs": "0.20.0",
|
||||||
"file-loader": "6.2.0",
|
|
||||||
"handlebars": "4.7.8",
|
"handlebars": "4.7.8",
|
||||||
"handlebars-loader": "1.7.3",
|
"html-bundler-webpack-plugin": "2.10.1",
|
||||||
"html-webpack-plugin": "5.5.3",
|
|
||||||
"husky": "^8.0.1",
|
"husky": "^8.0.1",
|
||||||
"image-webpack-loader": "8.1.0",
|
"image-webpack-loader": "8.1.0",
|
||||||
"is-ci-cli": "2.2.0",
|
"is-ci-cli": "2.2.0",
|
||||||
"jest": "29.6.2",
|
"jest": "29.6.2",
|
||||||
"lint-staged": "13.2.3",
|
"lint-staged": "13.2.3",
|
||||||
"markdown-toc": "^1.2.0",
|
"markdown-toc": "^1.2.0",
|
||||||
"mini-css-extract-plugin": "2.7.6",
|
|
||||||
"mkdirp": "3.0.1",
|
"mkdirp": "3.0.1",
|
||||||
"nopt": "7.2.0",
|
"nopt": "7.2.0",
|
||||||
"postcss": "8.4.27",
|
"postcss": "8.4.27",
|
||||||
|
|
@ -134,7 +131,6 @@
|
||||||
"ts-loader": "9.4.4",
|
"ts-loader": "9.4.4",
|
||||||
"ts-node": "10.9.1",
|
"ts-node": "10.9.1",
|
||||||
"typescript": "5.1.6",
|
"typescript": "5.1.6",
|
||||||
"url-loader": "4.1.1",
|
|
||||||
"webpack": "5.88.2",
|
"webpack": "5.88.2",
|
||||||
"webpack-cli": "5.1.4",
|
"webpack-cli": "5.1.4",
|
||||||
"webpack-dev-server": "4.15.1",
|
"webpack-dev-server": "4.15.1",
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,40 @@
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import HtmlBundlerPlugin from 'html-bundler-webpack-plugin';
|
||||||
import webpack from 'webpack';
|
|
||||||
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
|
||||||
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
|
||||||
// eslint-disable-next-line import/default
|
// eslint-disable-next-line import/default
|
||||||
import CopyPlugin from 'copy-webpack-plugin';
|
import CopyPlugin from 'copy-webpack-plugin';
|
||||||
|
|
||||||
const pages = ['index', 'demo'];
|
const config = {
|
||||||
|
output: {
|
||||||
type Plugin = ((this: webpack.Compiler, compiler: webpack.Compiler) => void) | webpack.WebpackPluginInstance;
|
path: path.resolve(__dirname, './docs'),
|
||||||
|
},
|
||||||
function plugins(page: string): Plugin[] {
|
resolve: {
|
||||||
return [
|
extensions: ['.tsx', '.ts', '.jsx', '.js'],
|
||||||
new MiniCssExtractPlugin({
|
},
|
||||||
filename: '[name].css',
|
plugins: [
|
||||||
chunkFilename: '[id].css',
|
new HtmlBundlerPlugin({
|
||||||
}),
|
entry: {
|
||||||
new HtmlWebpackPlugin({
|
// define templates here
|
||||||
hash: true,
|
index: './website/templates/pages/index/index.handlebars', // => docs/index.html,
|
||||||
inject: true,
|
demo: './website/templates/pages/demo/demo.handlebars', // => docs/demo.html
|
||||||
title: `${page} page`,
|
},
|
||||||
filename: `${page}.html`,
|
js: {
|
||||||
template: `./website/templates/pages/${page}/${page}.handlebars`,
|
// output filename of compiled JavaScript, used if `inline` option is false (defaults)
|
||||||
minify: {
|
filename: '[name].[contenthash:8].js',
|
||||||
|
//inline: true, // inlines JS into HTML
|
||||||
|
},
|
||||||
|
css: {
|
||||||
|
// output filename of extracted CSS, used if `inline` option is false (defaults)
|
||||||
|
filename: '[name].[contenthash:8].css',
|
||||||
|
//inline: true, // inlines CSS into HTML
|
||||||
|
},
|
||||||
|
preprocessor: 'handlebars', // use the handlebars compiler
|
||||||
|
preprocessorOptions: {
|
||||||
|
knownHelpersOnly: false,
|
||||||
|
helpers: [path.join(__dirname, 'website/templates/helpers')],
|
||||||
|
partials: [path.join(__dirname, 'website/templates/partials'), path.join(__dirname, 'website/templates/pages')],
|
||||||
|
},
|
||||||
|
minify: 'auto', // minify in production mode only
|
||||||
|
minifyOptions: {
|
||||||
html5: true,
|
html5: true,
|
||||||
collapseWhitespace: true,
|
collapseWhitespace: true,
|
||||||
caseSensitive: true,
|
caseSensitive: true,
|
||||||
|
|
@ -45,107 +57,74 @@ function plugins(page: string): Plugin[] {
|
||||||
{ from: 'website/sitemap.xml', to: 'sitemap.xml' },
|
{ from: 'website/sitemap.xml', to: 'sitemap.xml' },
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
];
|
],
|
||||||
}
|
module: {
|
||||||
|
rules: [
|
||||||
const config: webpack.Configuration[] = pages.map(page => {
|
{
|
||||||
return {
|
test: /\.tsx?$/,
|
||||||
entry: {
|
use: 'ts-loader',
|
||||||
[page]: `./website/templates/pages/${page}/${page}.ts`,
|
exclude: /node_modules/,
|
||||||
},
|
},
|
||||||
output: {
|
{
|
||||||
path: path.resolve(__dirname, './docs'),
|
test: /\.(gif|png|jpe?g|webp)$/i,
|
||||||
},
|
type: 'asset/resource',
|
||||||
resolve: {
|
generator: {
|
||||||
extensions: ['.tsx', '.ts', '.jsx', '.js'],
|
filename: 'images/[name][ext]?[hash]',
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.tsx?$/,
|
|
||||||
use: 'ts-loader',
|
|
||||||
exclude: /node_modules/,
|
|
||||||
},
|
},
|
||||||
{
|
use: [
|
||||||
test: /\.(html)$/,
|
{
|
||||||
use: {
|
loader: 'image-webpack-loader',
|
||||||
loader: 'html-loader',
|
|
||||||
options: {
|
options: {
|
||||||
attrs: ['img:src'],
|
mozjpeg: {
|
||||||
|
progressive: true,
|
||||||
|
quality: 65,
|
||||||
|
},
|
||||||
|
optipng: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
pngquant: {
|
||||||
|
quality: [0.65, 0.9],
|
||||||
|
speed: 4,
|
||||||
|
},
|
||||||
|
gifsicle: {
|
||||||
|
interlaced: false,
|
||||||
|
},
|
||||||
|
webp: {
|
||||||
|
quality: 75,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
{
|
},
|
||||||
test: /\.handlebars$/,
|
{
|
||||||
loader: 'handlebars-loader',
|
test: /\.(css)$/,
|
||||||
options: {
|
use: [{ loader: 'css-loader', options: { importLoaders: 1 } }, 'postcss-loader'],
|
||||||
inlineRequires: '/images/',
|
},
|
||||||
precompileOptions: {
|
{
|
||||||
knownHelpersOnly: false,
|
test: /\.woff(2)?(\?v=\d\.\d\.\d)?$/,
|
||||||
},
|
type: 'asset',
|
||||||
helperDirs: [path.join(__dirname, 'website/templates/helpers')],
|
parser: {
|
||||||
partialDirs: [path.join(__dirname, 'website/templates')],
|
dataUrlCondition: {
|
||||||
|
maxSize: 1000,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
test: /\.(gif|png|jpe?g|webp)$/i,
|
{
|
||||||
use: [
|
test: /\.(ttf|eot|svg)(\?v=\d\.\d\.\d)?$/,
|
||||||
{
|
type: 'asset/resource',
|
||||||
loader: 'file-loader',
|
},
|
||||||
options: {
|
],
|
||||||
name: '[name].[ext]?[hash]',
|
},
|
||||||
outputPath: 'images',
|
// enable live reload after changes
|
||||||
esModule: false,
|
devServer: {
|
||||||
},
|
static: path.resolve(__dirname, './docs'),
|
||||||
},
|
watchFiles: {
|
||||||
{
|
paths: ['website/**/*.*'],
|
||||||
loader: 'image-webpack-loader',
|
options: {
|
||||||
options: {
|
usePolling: true,
|
||||||
mozjpeg: {
|
},
|
||||||
progressive: true,
|
|
||||||
quality: 65,
|
|
||||||
},
|
|
||||||
optipng: {
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
pngquant: {
|
|
||||||
quality: [0.65, 0.9],
|
|
||||||
speed: 4,
|
|
||||||
},
|
|
||||||
gifsicle: {
|
|
||||||
interlaced: false,
|
|
||||||
},
|
|
||||||
webp: {
|
|
||||||
quality: 75,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(css)$/,
|
|
||||||
use: [MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { importLoaders: 1 } }, 'postcss-loader'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.woff(2)?(\?v=\d\.\d\.\d)?$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'url-loader',
|
|
||||||
options: {
|
|
||||||
limit: 1000,
|
|
||||||
mimetype: 'application/font-woff',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(ttf|eot|svg)(\?v=\d\.\d\.\d)?$/,
|
|
||||||
loader: 'file-loader',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
plugins: plugins(page),
|
},
|
||||||
};
|
};
|
||||||
});
|
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|
|
||||||
24
website/templates/helpers/block.js
Normal file
24
website/templates/helpers/block.js
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
|
const Handlebars = require('handlebars');
|
||||||
|
|
||||||
|
/** @typedef {import('handlebars').HelperOptions} HelperOptions */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} name
|
||||||
|
* @param {HelperOptions}
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
module.exports = function (name, options) {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
const context = this;
|
||||||
|
let partial = context._blocks[name] || options.fn;
|
||||||
|
|
||||||
|
if (typeof partial === 'string') {
|
||||||
|
partial = Handlebars.compile(partial);
|
||||||
|
context._blocks[name] = partial;
|
||||||
|
}
|
||||||
|
|
||||||
|
return partial(context, { data: options.hash });
|
||||||
|
};
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
import handlebars, { HelperOptions } from 'handlebars';
|
|
||||||
|
|
||||||
const loadPartial = <T>(name: string): handlebars.Template<T> => {
|
|
||||||
let partial = handlebars.partials[name];
|
|
||||||
if (typeof partial === 'string') {
|
|
||||||
partial = handlebars.compile(partial);
|
|
||||||
handlebars.partials[name] = partial;
|
|
||||||
}
|
|
||||||
return partial;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default (name: string, options: HelperOptions): string => {
|
|
||||||
const partial = loadPartial(name) || options.fn;
|
|
||||||
return partial(this, { data: options.hash });
|
|
||||||
};
|
|
||||||
20
website/templates/helpers/partial.js
Normal file
20
website/templates/helpers/partial.js
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/** @typedef {import('handlebars').HelperOptions} HelperOptions */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} name
|
||||||
|
* @param {HelperOptions} options
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
module.exports = function (name, options) {
|
||||||
|
// don't modify `this` in code directly, because it will be compiled in `exports` as an immutable object
|
||||||
|
// eslint-disable-next-line
|
||||||
|
const context = this;
|
||||||
|
|
||||||
|
if (!context._blocks) {
|
||||||
|
context._blocks = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
context._blocks[name] = options.fn;
|
||||||
|
};
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
import handlebars, { HelperOptions } from 'handlebars';
|
|
||||||
|
|
||||||
export default (name: string, options: HelperOptions): void => {
|
|
||||||
handlebars.registerPartial(name, options.fn);
|
|
||||||
};
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
{{#partial "content"}}
|
{{#partial 'scripts'}}
|
||||||
{{> content}}
|
{{! define here page-specific source script files }}
|
||||||
|
<script src="./demo.ts" defer="defer"></script>
|
||||||
{{/partial}}
|
{{/partial}}
|
||||||
{{> ../../template}}
|
{{#partial "content"}}
|
||||||
|
{{> demo/content}}
|
||||||
|
{{/partial}}
|
||||||
|
{{> template}}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { Diff2HtmlUI, defaultDiff2HtmlUIConfig, Diff2HtmlUIConfig } from '../../../../src/ui/js/diff2html-ui-slim';
|
import { Diff2HtmlUI, defaultDiff2HtmlUIConfig, Diff2HtmlUIConfig } from '../../../../src/ui/js/diff2html-ui-slim';
|
||||||
|
|
||||||
import '../../../main.ts';
|
import '../../../main';
|
||||||
import '../../../main.css';
|
import '../../../main.css';
|
||||||
import 'highlight.js/styles/github.css';
|
import 'highlight.js/styles/github.css';
|
||||||
import '../../../../src/ui/css/diff2html.css';
|
import '../../../../src/ui/css/diff2html.css';
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
{{#partial "content"}}
|
{{#partial 'scripts'}}
|
||||||
{{> content}}
|
{{! define here page-specific source script files }}
|
||||||
|
<script src="./index.ts" defer="defer"></script>
|
||||||
{{/partial}}
|
{{/partial}}
|
||||||
{{> ../../template}}
|
{{#partial "content"}}
|
||||||
|
{{> index/content}}
|
||||||
|
{{/partial}}
|
||||||
|
{{> template}}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import Clipboard from 'clipboard';
|
import Clipboard from 'clipboard';
|
||||||
|
|
||||||
import '../../../main.ts';
|
import '../../../main';
|
||||||
import '../../../main.css';
|
import '../../../main.css';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@
|
||||||
ga('create', 'UA-78351861-2', 'auto');
|
ga('create', 'UA-78351861-2', 'auto');
|
||||||
ga('send', 'pageview');
|
ga('send', 'pageview');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
{{#block 'scripts'}}{{/block}}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
Loading…
Reference in a new issue