Skip to content

Commit

Permalink
convert webpack configuration into typescript (#45)
Browse files Browse the repository at this point in the history
  • Loading branch information
melledijkstra authored Oct 28, 2024
1 parent 074db7b commit dc23e02
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 48 deletions.
22 changes: 17 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,11 @@
"@storybook/test": "^8.3.6",
"@storybook/types": "^8.3.6",
"@types/google-apps-script": "^1.0.84",
"@types/node": "^22.8.1",
"@types/papaparse": "^5.3.15",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/webpack": "^5.28.5",
"@vitest/coverage-v8": "^2.1.3",
"babel-loader": "^9.2.1",
"babel-plugin-import": "^1.13.8",
Expand Down
104 changes: 61 additions & 43 deletions webpack.config.cjs → webpack.config.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
/*********************************
* import webpack plugins
********************************/
const path = require('path');
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const GasPlugin = require('gas-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackInlineSourcePlugin = require('@effortlessmotion/html-webpack-inline-source-plugin');
const DynamicCdnWebpackPlugin = require('@effortlessmotion/dynamic-cdn-webpack-plugin');
const moduleToCdn = require('module-to-cdn');
import path from 'path';
import { DefinePlugin, Configuration } from 'webpack';
import CopyWebpackPlugin from 'copy-webpack-plugin';
import GasPlugin from 'gas-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import HtmlWebpackInlineSourcePlugin from '@effortlessmotion/html-webpack-inline-source-plugin';
import DynamicCdnWebpackPlugin from '@effortlessmotion/dynamic-cdn-webpack-plugin';
import moduleToCdn from 'module-to-cdn';

const isProd = process.env.NODE_ENV === 'production';

Expand All @@ -28,8 +28,16 @@ const envVars = {};
/*********************************
* define entrypoints
********************************/

type EntryPoint = {
name: string;
entry: string;
filename: string;
template: string;
};

// IF UPDATE HERE, ALSO UPDATE 'server/ui.ts' !
const clientEntrypoints = [
const clientEntrypoints: Array<EntryPoint> = [
{
name: 'CLIENT - About Dialog',
entry: './src/client/about-dialog/index.tsx',
Expand All @@ -55,7 +63,7 @@ const clientEntrypoints = [
********************************/

// webpack settings for copying files to the destination folder
const copyFilesConfig = {
const copyFilesConfig: Configuration = {
name: 'COPY FILES - appsscript.json',
mode: 'production', // unnecessary for this config, but removes console warning
entry: copyAppscriptEntry,
Expand All @@ -76,12 +84,12 @@ const copyFilesConfig = {
};

// webpack settings used by both client and server
const sharedClientAndServerConfig = {
const sharedClientAndServerConfig: Partial<Configuration> = {
context: __dirname,
};

// webpack settings used by all client entrypoints
const clientConfig = () => ({
const clientConfig: Partial<Configuration> = {
...sharedClientAndServerConfig,
mode: isProd ? 'production' : 'development',
output: {
Expand Down Expand Up @@ -125,15 +133,22 @@ const clientConfig = () => ({
},
],
},
});
};

type DynamicCDNEntry = {
name: string;
var: string;
version: string;
url: string;
};

// DynamicCdnWebpackPlugin settings
// these settings help us load 'react', 'react-dom' and the packages defined below from a CDN
// see https://github.com/enuchi/React-Google-Apps-Script#adding-new-libraries-and-packages
const DynamicCdnWebpackPluginConfig = {
// set "verbose" to true to print console logs on CDN usage while webpack builds
verbose: false,
resolver: (packageName, packageVersion, options) => {
resolver: (packageName, packageVersion, options): DynamicCDNEntry | null => {
const moduleDetails = moduleToCdn(packageName, packageVersion, options);
const packageSuffix = isProd ? '.min.js' : '.js';

Expand Down Expand Up @@ -200,34 +215,36 @@ const DynamicCdnWebpackPluginConfig = {
};

// webpack settings used by each client entrypoint defined at top
const clientConfigs = clientEntrypoints.map((clientEntrypoint) => {
return {
...clientConfig(),
name: clientEntrypoint.name,
entry: clientEntrypoint.entry,
plugins: [
new webpack.DefinePlugin({
'process.env': JSON.stringify(envVars),
}),
// when analyzing bundle we don't want to inline the code
// otherwise bundle analyzer can't inspect the different modules
new HtmlWebpackPlugin({
template: clientEntrypoint.template,
filename: `${clientEntrypoint.filename}.html`,
inlineSource: '^/.*(js|css)$', // embed all js and css inline, exclude packages from dynamic cdn insertion
scriptLoading: 'blocking',
inject: 'body',
}),
// this plugin allows us to add dynamically load packages from a CDN
new DynamicCdnWebpackPlugin(DynamicCdnWebpackPluginConfig),
// add the generated js code to the html file inline
new HtmlWebpackInlineSourcePlugin(),
].filter(Boolean),
};
});
const clientConfigs = clientEntrypoints.map<Configuration>(
(clientEntrypoint) => {
return {
...clientConfig,
name: clientEntrypoint.name,
entry: clientEntrypoint.entry,
plugins: [
new DefinePlugin({
'process.env': JSON.stringify(envVars),
}),
// when analyzing bundle we don't want to inline the code
// otherwise bundle analyzer can't inspect the different modules
new HtmlWebpackPlugin({
template: clientEntrypoint.template,
filename: `${clientEntrypoint.filename}.html`,
inlineSource: '^/.*(js|css)$', // embed all js and css inline, exclude packages from dynamic cdn insertion
scriptLoading: 'blocking',
inject: 'body',
}),
// this plugin allows us to add dynamically load packages from a CDN
new DynamicCdnWebpackPlugin(DynamicCdnWebpackPluginConfig),
// add the generated js code to the html file inline
new HtmlWebpackInlineSourcePlugin(),
].filter(Boolean),
};
}
);

// webpack settings used by the server-side code
const serverConfig = {
const serverConfig: Configuration = {
...sharedClientAndServerConfig,
name: 'SERVER',
// server config can't use 'development' mode
Expand Down Expand Up @@ -275,12 +292,13 @@ const serverConfig = {
],
};

module.exports = [
const config: Array<Configuration> = [
// 1. Copy appsscript.json to destination,
{ ...copyFilesConfig },
copyFilesConfig,
// 2. Create the server bundle. Don't serve server bundle when running webpack serve.
serverConfig,
// 3. Create one client bundle for each client entrypoint.
...clientConfigs,
].filter(Boolean);
module.exports.parallelism = 2;

export default config;

0 comments on commit dc23e02

Please sign in to comment.