1 import HtmlWebpackPlugin from 'html-webpack-plugin';
2 // eslint-disable-next-line lodash/import-scope
3 import template from 'lodash.template';
4 import path from 'path';
5 import type webpack from 'webpack';
6 import 'webpack-dev-server';
8 import getConfig from '@proton/pack/webpack.config';
9 import CopyIndexHtmlWebpackPlugin from '@proton/pack/webpack/copy-index-html-webpack-plugin';
10 import { addDevEntry, getIndexChunks, getSupportedEntry } from '@proton/pack/webpack/entries';
12 import type { HrefLang } from './pages/interface';
13 import { getPages } from './pages/pages';
14 import type { Parameters } from './src/pages/interface';
16 const getTemplateParameters = (
17 originalTemplateParameters: any,
18 hreflangs: HrefLang[],
19 shortLocalizedPathname: string,
20 parameters: Parameters & { pathname: string }
22 let url = originalTemplateParameters.url;
23 const origin = url.replace(/\/$/, '');
24 if (parameters.pathname) {
25 url = `${origin}${parameters.pathname}`;
28 ...originalTemplateParameters,
31 hreflangs: hreflangs.map(({ hreflang, pathname }) => {
34 href: `${origin}${pathname}${parameters.pathname.replace(shortLocalizedPathname, '')}`,
40 const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
41 const smp = new SpeedMeasurePlugin();
43 const result = async (env: any): Promise<webpack.Configuration> => {
44 const pagePromise = getPages();
46 const config = getConfig(env);
48 const plugins = config.plugins || [];
49 config.plugins = plugins;
51 const htmlPlugin = plugins.find((plugin): plugin is HtmlWebpackPlugin => {
52 return plugin instanceof HtmlWebpackPlugin;
55 throw new Error('Missing html plugin');
57 const htmlIndex = plugins.indexOf(htmlPlugin);
58 const originalTemplateParameters = htmlPlugin.userOptions.templateParameters as { [key: string]: any };
60 const { pre, unsupported } = config.entry as any;
62 if (env.appMode === 'standalone') {
65 ['private-index']: [path.resolve('./src/app/private.tsx'), getSupportedEntry()],
72 new HtmlWebpackPlugin({
73 filename: 'index.html',
74 template: path.resolve('./src/private.ejs'),
75 templateParameters: originalTemplateParameters,
76 scriptLoading: 'defer' as const,
77 chunks: getIndexChunks('private-index'),
78 inject: 'body' as const,
89 ['private-index']: [path.resolve('./src/app/private.tsx'), getSupportedEntry()],
90 ['public-index']: [path.resolve('./src/app/public.tsx'), getSupportedEntry()],
91 ['lite-index']: [path.resolve('./src/lite/index.tsx'), getSupportedEntry()],
92 storage: path.resolve('./src/app/storage.ts'),
96 const rewrites: any[] = [];
98 config.devServer.historyApiFallback.rewrites = rewrites;
100 // Replace the old html webpack plugin with this
104 new HtmlWebpackPlugin({
105 filename: 'private.html',
106 template: path.resolve('./src/private.ejs'),
107 templateParameters: originalTemplateParameters,
108 scriptLoading: 'defer' as const,
109 chunks: getIndexChunks('private-index'),
110 inject: 'body' as const,
113 rewrites.push({ from: /^\/u\//, to: '/private.html' });
118 new HtmlWebpackPlugin({
119 filename: 'index.html',
120 template: path.resolve('./src/public.ejs'),
121 templateParameters: originalTemplateParameters,
122 scriptLoading: 'defer',
123 chunks: getIndexChunks('public-index'),
131 new HtmlWebpackPlugin({
132 filename: 'storage.html',
133 template: path.resolve('./src/storage.ejs'),
134 templateParameters: originalTemplateParameters,
135 scriptLoading: 'defer',
141 rewrites.push({ from: /^\/lite/, to: '/lite/index.html' });
145 new HtmlWebpackPlugin({
146 filename: 'lite/index.html',
147 template: path.resolve('./src/lite.ejs'),
148 templateParameters: originalTemplateParameters,
149 scriptLoading: 'defer',
150 chunks: getIndexChunks('lite-index'),
155 const { pages, hreflangs } = await pagePromise;
157 pages.forEach(({ rewrite }) => {
158 rewrites.push(rewrite);
162 new CopyIndexHtmlWebpackPlugin((source) => {
163 const compiled = template(
165 // Note: We use two different template interpolations, due to <%= require('./favicon.svg' %>, which requires
166 // a lot more effort to support properly, so we use the default loader for that and our own loader for this.
168 evaluate: /\{\{([\s\S]+?)\}\}/g,
169 interpolate: /\{\{=([\s\S]+?)\}\}/g,
170 escape: /\{\{-([\s\S]+?)\}\}/g,
178 getTemplateParameters(originalTemplateParameters, hreflangs, '', {
179 title: originalTemplateParameters.appName,
180 description: originalTemplateParameters.description,
186 const rest = pages.map(({ shortLocalizedPathname, filename, parameters }) => {
190 getTemplateParameters(originalTemplateParameters, hreflangs, shortLocalizedPathname, parameters)
194 return [index, ...rest];
202 export default result;