1 import HtmlWebpackPlugin from 'html-webpack-plugin';
2 import template from 'lodash.template';
3 import { readFileSync } from 'node:fs';
4 import * as path from 'node:path';
5 import type { HrefLang } from 'proton-account/pages/interface';
6 import { getPages } from 'proton-account/pages/pages';
7 import type { Parameters } from 'proton-account/src/pages/interface';
8 import type { Configuration } from 'webpack';
9 import 'webpack-dev-server';
11 import getConfig from '@proton/pack/webpack.config';
12 import CopyIndexHtmlWebpackPlugin from '@proton/pack/webpack/copy-index-html-webpack-plugin';
14 const getTemplateParameters = (
15 originalTemplateParameters: any,
16 hreflangs: HrefLang[],
17 shortLocalizedPathname: string,
18 parameters: Parameters & { pathname: string }
20 let url = originalTemplateParameters.url;
21 const origin = url.replace(/\/$/, '');
22 if (parameters.pathname) {
23 url = `${origin}${parameters.pathname}`;
26 ...originalTemplateParameters,
29 hreflangs: hreflangs.map(({ hreflang, pathname }) => {
32 href: `${origin}${pathname}${parameters.pathname.replace(shortLocalizedPathname, '')}`,
38 const result = async (env: any): Promise<Configuration> => {
39 const pagesPromise = getPages();
40 const config = getConfig(env);
41 const plugins = config.plugins || [];
42 config.plugins = plugins;
44 const htmlPlugin = plugins.find((plugin): plugin is HtmlWebpackPlugin => {
45 return plugin instanceof HtmlWebpackPlugin;
48 throw new Error('Missing html plugin');
51 const rewrites: any[] = [];
53 config.devServer.historyApiFallback.rewrites = rewrites;
55 const originalTemplateParameters = htmlPlugin.userOptions.templateParameters as { [key: string]: any };
57 const { pages, hreflangs } = await pagesPromise;
59 pages.forEach(({ rewrite }) => {
60 rewrites.push(rewrite);
64 new CopyIndexHtmlWebpackPlugin((source) => {
65 const compiled = template(
67 // Note: We use two different template interpolations, due to <%= require('./favicon.svg' %>, which requires
68 // a lot more effort to support properly, so we use the default loader for that and our own loader for this.
70 evaluate: /\{\{([\s\S]+?)\}\}/g,
71 interpolate: /\{\{=([\s\S]+?)\}\}/g,
72 escape: /\{\{-([\s\S]+?)\}\}/g,
80 getTemplateParameters(originalTemplateParameters, hreflangs, '', {
81 title: originalTemplateParameters.appName,
82 description: originalTemplateParameters.description,
88 const rest = pages.map(({ shortLocalizedPathname, filename, parameters }) => {
92 getTemplateParameters(originalTemplateParameters, hreflangs, shortLocalizedPathname, parameters)
97 const result = [index, ...rest];
98 const convertSnippet = readFileSync(path.resolve('./src/convert-snippet.html'))
102 return result.flatMap((result) => {
103 const convertEntry = {
104 name: result.name.replace('.html', '.convert.html'),
105 data: result.data.replace('</title>', `</title>${convertSnippet}`),
108 return [result, convertEntry];
116 export default result;