85223ca42a
- Update missing dev dependencies - Fix root .eslintrc.json and client and server versions - Add lint.yaml workflow - Remove babel settings - Clean up and fix eslint and ts errors
216 lines
6.7 KiB
TypeScript
216 lines
6.7 KiB
TypeScript
/* eslint-disable import/no-extraneous-dependencies */
|
|
import { resolve } from 'path';
|
|
import { BuildOptions, ServerOptions, build, defineConfig } from 'vite';
|
|
import { existsSync, readFileSync } from 'fs';
|
|
import react from '@vitejs/plugin-react-swc';
|
|
import { viteStaticCopy } from 'vite-plugin-static-copy';
|
|
import { viteSingleFile } from 'vite-plugin-singlefile';
|
|
import { writeFile } from 'fs/promises';
|
|
|
|
const PORT = 3000;
|
|
const clientRoot = './src/client';
|
|
const outDir = './dist';
|
|
const serverEntry = 'src/server/index.ts';
|
|
const copyAppscriptEntry = './appsscript.json';
|
|
const devServerWrapper = './dev/dev-server-wrapper.html';
|
|
|
|
const clientEntrypoints = [
|
|
{
|
|
name: 'CLIENT - Dialog Demo',
|
|
filename: 'dialog-demo', // we'll add the .html suffix to these
|
|
template: 'dialog-demo/index.html',
|
|
},
|
|
{
|
|
name: 'CLIENT - Dialog Demo Bootstrap',
|
|
filename: 'dialog-demo-bootstrap',
|
|
template: 'dialog-demo-bootstrap/index.html',
|
|
},
|
|
{
|
|
name: 'CLIENT - Dialog Demo MUI',
|
|
filename: 'dialog-demo-mui',
|
|
template: 'dialog-demo-mui/index.html',
|
|
},
|
|
{
|
|
name: 'CLIENT - Dialog Demo Tailwind CSS',
|
|
filename: 'dialog-demo-tailwindcss',
|
|
template: 'dialog-demo-tailwindcss/index.html',
|
|
},
|
|
{
|
|
name: 'CLIENT - Sidebar About Page',
|
|
filename: 'sidebar-about-page',
|
|
template: 'sidebar-about-page/index.html',
|
|
},
|
|
];
|
|
|
|
const keyPath = resolve(__dirname, './certs/key.pem');
|
|
const certPath = resolve(__dirname, './certs/cert.pem');
|
|
const pfxPath = resolve(__dirname, './certs/cert.pfx'); // if needed for Windows
|
|
|
|
const devServerOptions: ServerOptions = {
|
|
port: PORT,
|
|
};
|
|
|
|
// use key and cert settings only if they are found
|
|
if (existsSync(keyPath) && existsSync(certPath)) {
|
|
devServerOptions.https = {
|
|
key: readFileSync(resolve(__dirname, './certs/key.pem')),
|
|
cert: readFileSync(resolve(__dirname, './certs/cert.pem')),
|
|
};
|
|
}
|
|
|
|
// If mkcert -install cannot be used on Windows machines (in pipeline, for example), the
|
|
// script at scripts/generate-cert.ps1 can be used to create a .pfx cert
|
|
if (existsSync(pfxPath)) {
|
|
// use pfx file if it's found
|
|
devServerOptions.https = {
|
|
pfx: readFileSync(pfxPath),
|
|
passphrase: 'abc123',
|
|
};
|
|
}
|
|
|
|
const clientServeConfig = () =>
|
|
defineConfig({
|
|
plugins: [react()],
|
|
server: devServerOptions,
|
|
root: clientRoot,
|
|
});
|
|
|
|
const clientBuildConfig = ({
|
|
clientEntrypointRoot,
|
|
template,
|
|
}: {
|
|
clientEntrypointRoot: string;
|
|
template: string;
|
|
}) =>
|
|
defineConfig({
|
|
plugins: [react(), viteSingleFile({ useRecommendedBuildConfig: true })],
|
|
root: resolve(__dirname, clientRoot, clientEntrypointRoot),
|
|
build: {
|
|
sourcemap: false,
|
|
write: false, // don't write to disk
|
|
outDir,
|
|
emptyOutDir: true,
|
|
minify: true,
|
|
rollupOptions: {
|
|
external: [
|
|
'react',
|
|
'react-dom',
|
|
'react-transition-group',
|
|
'react-bootstrap',
|
|
'@mui/material',
|
|
'@emotion/react',
|
|
'@emotion/styled',
|
|
'gas-client',
|
|
'@types/react',
|
|
],
|
|
output: {
|
|
format: 'iife', // needed to use globals from UMD builds
|
|
dir: outDir,
|
|
globals: {
|
|
react: 'React',
|
|
'react-dom': 'ReactDOM',
|
|
'react-transition-group': 'ReactTransitionGroup',
|
|
'react-bootstrap': 'ReactBootstrap',
|
|
'@mui/material': 'MaterialUI',
|
|
'@emotion/react': 'emotionReact',
|
|
'@emotion/styled': 'emotionStyled',
|
|
'gas-client': 'GASClient',
|
|
'@types/react': '@types/react',
|
|
},
|
|
},
|
|
input: resolve(__dirname, clientRoot, template),
|
|
},
|
|
},
|
|
});
|
|
|
|
const serverBuildConfig: BuildOptions = {
|
|
emptyOutDir: true,
|
|
minify: false, // needed to work with footer
|
|
lib: {
|
|
entry: resolve(__dirname, serverEntry),
|
|
fileName: 'code',
|
|
name: 'globalThis',
|
|
formats: ['iife'],
|
|
},
|
|
rollupOptions: {
|
|
output: {
|
|
entryFileNames: 'code.js',
|
|
extend: true,
|
|
footer: (chunk) =>
|
|
chunk.exports
|
|
.map((exportedFunction) => `function ${exportedFunction}() {};`)
|
|
.join('\n'),
|
|
},
|
|
},
|
|
};
|
|
|
|
const buildConfig = ({ mode }: { mode: string }) => {
|
|
const targets = [{ src: copyAppscriptEntry, dest: './' }];
|
|
if (mode === 'development') {
|
|
targets.push(
|
|
...clientEntrypoints.map((entrypoint) => ({
|
|
src: devServerWrapper,
|
|
dest: './',
|
|
rename: `${entrypoint.filename}.html`,
|
|
transform: (contents: string) =>
|
|
contents
|
|
.toString()
|
|
.replace(/__PORT__/g, String(PORT))
|
|
.replace(/__FILE_NAME__/g, entrypoint.template),
|
|
}))
|
|
);
|
|
}
|
|
return defineConfig({
|
|
plugins: [
|
|
viteStaticCopy({
|
|
targets,
|
|
}),
|
|
/**
|
|
* This builds the client react app bundles for production, and writes them to disk.
|
|
* Because multiple client entrypoints (dialogs) are built, we need to loop through
|
|
* each entrypoint and build the client bundle for each. Vite doesn't have great tooling for
|
|
* building multiple single-page apps in one project, so we have to do this manually with a
|
|
* post-build closeBundle hook (https://rollupjs.org/guide/en/#closebundle).
|
|
*/
|
|
mode === 'production' && {
|
|
name: 'build-client-production-bundles',
|
|
closeBundle: async () => {
|
|
console.log('Building client production bundles...');
|
|
// eslint-disable-next-line no-restricted-syntax
|
|
for (const clientEntrypoint of clientEntrypoints) {
|
|
console.log('Building client bundle for', clientEntrypoint.name);
|
|
// eslint-disable-next-line no-await-in-loop
|
|
const buildOutput = await build(
|
|
clientBuildConfig({
|
|
clientEntrypointRoot: clientEntrypoint.filename,
|
|
template: clientEntrypoint.template,
|
|
})
|
|
);
|
|
// eslint-disable-next-line no-await-in-loop
|
|
await writeFile(
|
|
resolve(__dirname, outDir, `${clientEntrypoint.filename}.html`),
|
|
// @ts-expect-error - output is an array of RollupOutput
|
|
buildOutput.output[0].source
|
|
);
|
|
}
|
|
console.log('Finished building client bundles!');
|
|
},
|
|
},
|
|
].filter(Boolean),
|
|
build: serverBuildConfig,
|
|
});
|
|
};
|
|
|
|
// https://vitejs.dev/config/
|
|
export default async ({ command, mode }: { command: string; mode: string }) => {
|
|
if (command === 'serve') {
|
|
// for 'serve' mode, we only want to serve the client bundle locally
|
|
return clientServeConfig();
|
|
}
|
|
if (command === 'build') {
|
|
// for 'build' mode, we have two paths: build assets for local development, and build for production
|
|
return buildConfig({ mode });
|
|
}
|
|
return {};
|
|
};
|