Merge branch 'fix-mail-constant' into 'main'
[ProtonMail-WebClient.git] / applications / account / webpack.config.ts
blob47b1d60b288c426fb31444704ca1a1807ce766f7
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 }
21 ) => {
22     let url = originalTemplateParameters.url;
23     const origin = url.replace(/\/$/, '');
24     if (parameters.pathname) {
25         url = `${origin}${parameters.pathname}`;
26     }
27     return {
28         ...originalTemplateParameters,
29         ...parameters,
30         url,
31         hreflangs: hreflangs.map(({ hreflang, pathname }) => {
32             return {
33                 hreflang,
34                 href: `${origin}${pathname}${parameters.pathname.replace(shortLocalizedPathname, '')}`,
35             };
36         }),
37     };
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;
53     });
54     if (!htmlPlugin) {
55         throw new Error('Missing html plugin');
56     }
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') {
63         config.entry = {
64             pre,
65             ['private-index']: [path.resolve('./src/app/private.tsx'), getSupportedEntry()],
66             unsupported,
67         };
69         plugins.splice(
70             htmlIndex,
71             1,
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,
79             })
80         );
82         addDevEntry(config);
84         return config;
85     }
87     config.entry = {
88         pre,
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'),
93         unsupported,
94     };
96     const rewrites: any[] = [];
97     // @ts-ignore
98     config.devServer.historyApiFallback.rewrites = rewrites;
100     // Replace the old html webpack plugin with this
101     plugins.splice(
102         htmlIndex,
103         1,
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,
111         })
112     );
113     rewrites.push({ from: /^\/u\//, to: '/private.html' });
115     plugins.splice(
116         htmlIndex,
117         0,
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'),
124             inject: 'body',
125         })
126     );
128     plugins.splice(
129         htmlIndex,
130         0,
131         new HtmlWebpackPlugin({
132             filename: 'storage.html',
133             template: path.resolve('./src/storage.ejs'),
134             templateParameters: originalTemplateParameters,
135             scriptLoading: 'defer',
136             chunks: ['storage'],
137             inject: 'body',
138         })
139     );
141     rewrites.push({ from: /^\/lite/, to: '/lite/index.html' });
142     plugins.splice(
143         htmlIndex,
144         0,
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'),
151             inject: 'body',
152         })
153     );
155     const { pages, hreflangs } = await pagePromise;
157     pages.forEach(({ rewrite }) => {
158         rewrites.push(rewrite);
159     });
161     plugins.push(
162         new CopyIndexHtmlWebpackPlugin((source) => {
163             const compiled = template(
164                 source,
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.
167                 {
168                     evaluate: /\{\{([\s\S]+?)\}\}/g,
169                     interpolate: /\{\{=([\s\S]+?)\}\}/g,
170                     escape: /\{\{-([\s\S]+?)\}\}/g,
171                 },
172                 undefined
173             );
175             const index = {
176                 name: 'index.html',
177                 data: compiled(
178                     getTemplateParameters(originalTemplateParameters, hreflangs, '', {
179                         title: originalTemplateParameters.appName,
180                         description: originalTemplateParameters.description,
181                         pathname: '/',
182                     })
183                 ),
184             };
186             const rest = pages.map(({ shortLocalizedPathname, filename, parameters }) => {
187                 return {
188                     name: filename,
189                     data: compiled(
190                         getTemplateParameters(originalTemplateParameters, hreflangs, shortLocalizedPathname, parameters)
191                     ),
192                 };
193             });
194             return [index, ...rest];
195         })
196     );
198     plugins.push(smp);
199     return config;
202 export default result;