Skip to content

Commit

Permalink
Use ES modules in order to optimize frontend bundles (#46)
Browse files Browse the repository at this point in the history
* changed webpack + babel configurations in order to allow ES modules

* updated webpack config to generate CDN ES modules

* fix build issues by reverting upgrade of packages
  • Loading branch information
melledijkstra authored Oct 30, 2024
1 parent dc23e02 commit 521ee58
Show file tree
Hide file tree
Showing 14 changed files with 567 additions and 511 deletions.
1 change: 1 addition & 0 deletions .claspignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ node_modules/**
# this is a generated file that will be inlined within the generated HTML
# no need to deploy it
main.js
*.txt
6 changes: 5 additions & 1 deletion babel.config.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"sourceType": "unambiguous",
"presets": ["@babel/preset-env", "@babel/preset-typescript"]
"presets": [
"@babel/preset-env",
// let babel handle typescript compilation for both projects
"@babel/preset-typescript"
]
}
882 changes: 484 additions & 398 deletions package-lock.json

Large diffs are not rendered by default.

9 changes: 3 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
{
"name": "gas-fire",
"version": "2.0.2",
"version": "2.1.0",
"author": "Melle Dijkstra",
"description": "Google App Script utilities to automate the FIRE google sheet",
"license": "MIT",
"private": true,
"type": "module",
"sideEffects": false,
"workspaces": [
"client",
"server"
Expand All @@ -18,7 +16,7 @@
"publish": "clasp push -f",
"dev": "npm run storybook",
"analyze:server": "ANALYZE=true webpack --config-name SERVER --profile --json > dist/stats.json && webpack-bundle-analyzer dist/stats.json",
"analyze:client": "ANALYZE=true webpack --config-name 'CLIENT - Import Dialog' --profile --json > dist/stats.json && webpack-bundle-analyzer dist/stats.json",
"analyze:client": "ANALYZE=true webpack --config-name 'CLIENT:import' --profile --json > dist/stats.json && webpack-bundle-analyzer dist/stats.json",
"build": "NODE_ENV=production webpack --progress",
"deploy": "rm -rf dist && npm run build && npm run publish",
"test": "vitest",
Expand All @@ -42,7 +40,7 @@
"@babel/preset-react": "^7.25.9",
"@babel/preset-typescript": "^7.25.9",
"@effortlessmotion/dynamic-cdn-webpack-plugin": "^5.0.1",
"@effortlessmotion/html-webpack-inline-source-plugin": "^1.0.3",
"html-inline-script-webpack-plugin": "^3.2.1",
"@google/clasp": "^2.4.2",
"@storybook/addon-essentials": "^8.3.6",
"@storybook/addon-interactions": "^8.3.6",
Expand All @@ -61,7 +59,6 @@
"@types/webpack": "^5.28.5",
"@vitest/coverage-v8": "^2.1.3",
"babel-loader": "^9.2.1",
"babel-plugin-import": "^1.13.8",
"copy-webpack-plugin": "^12.0.2",
"css-loader": "^7.1.2",
"gas-client": "^1.1.1",
Expand Down
37 changes: 0 additions & 37 deletions src/client/.babelrc

This file was deleted.

16 changes: 16 additions & 0 deletions src/client/.babelrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"sourceType": "module",
"presets": [
[
"@babel/preset-env",
{
// prevent babel from transforming ES modules
"modules": false,
"targets": {
"esmodules": true
}
}
],
["@babel/preset-react", { "runtime": "classic" }]
]
}
6 changes: 4 additions & 2 deletions src/client/Application.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { ScopedCssBaseline } from '@mui/material';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import { blue, green } from '@mui/material/colors';
import { ThemeProvider, createTheme } from '@mui/material';
import { colors } from '@mui/material';
import { ReactNode } from 'react';

const { green, blue } = colors;

export const Application = ({ children }: { children: ReactNode }) => {
const theme = createTheme({
palette: {
Expand Down
11 changes: 0 additions & 11 deletions src/common/.babelrc

This file was deleted.

11 changes: 0 additions & 11 deletions src/server/.babelrc

This file was deleted.

3 changes: 3 additions & 0 deletions src/server/.babelrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env", "@babel/preset-typescript"]
}
2 changes: 1 addition & 1 deletion src/server/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Functions to setup the initial UI
export {
onOpen,
fileUploadDialog,
openFileUploadDialog,
openSettingsDialog,
openAboutDialog,
} from './ui';
Expand Down
8 changes: 4 additions & 4 deletions src/server/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { DIALOG_SIZES } from '../common/constants';
export function onOpen(): void {
const ui = SpreadsheetApp.getUi();
ui.createMenu('Import')
.addItem('Upload CSV', 'fileUploadDialog')
.addItem('Settings', 'openSettingsDialog')
.addItem('About', 'openAboutDialog')
.addItem('Upload CSV', openFileUploadDialog.name)
.addItem('Settings', openSettingsDialog.name)
.addItem('About', openAboutDialog.name)
.addToUi();
}

export function fileUploadDialog(): void {
export function openFileUploadDialog(): void {
const [width, height] = DIALOG_SIZES.import;
// Make sure that the file name here is correct with the output when generating the bundle!
const html = HtmlService.createTemplateFromFile('import-dialog')
Expand Down
6 changes: 4 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
{
"compilerOptions": {
"strict": true,
"moduleResolution": "Node",
"moduleResolution": "Bundler",
"allowSyntheticDefaultImports": true,
"module": "ES6",
"esModuleInterop": true,
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"lib": ["ES2023", "DOM", "DOM.Iterable"],
"types": ["gas-types-detailed", "vitest/globals"],
"jsx": "react-jsx"
},
Expand Down
80 changes: 42 additions & 38 deletions webpack.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ 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 HtmlInlineScriptPlugin from 'html-inline-script-webpack-plugin';
import DynamicCdnWebpackPlugin from '@effortlessmotion/dynamic-cdn-webpack-plugin';
import moduleToCdn from 'module-to-cdn';

Expand Down Expand Up @@ -39,19 +39,19 @@ type EntryPoint = {
// IF UPDATE HERE, ALSO UPDATE 'server/ui.ts' !
const clientEntrypoints: Array<EntryPoint> = [
{
name: 'CLIENT - About Dialog',
name: 'CLIENT:about',
entry: './src/client/about-dialog/index.tsx',
filename: 'about-dialog', // we'll add the .html suffix to these
template: './src/client/about-dialog/index.html',
},
{
name: 'CLIENT - Import Dialog',
name: 'CLIENT:import',
entry: './src/client/import-dialog/index.tsx',
filename: 'import-dialog', // we'll add the .html suffix to these
template: './src/client/import-dialog/index.html',
},
{
name: 'CLIENT - Settings Dialog',
name: 'CLIENT:settings',
entry: './src/client/settings-dialog/index.tsx',
filename: 'settings-dialog', // we'll add the .html suffix to these
template: './src/client/settings-dialog/index.html',
Expand Down Expand Up @@ -98,6 +98,14 @@ const clientConfig: Partial<Configuration> = {
// and should be put in .claspignore so it is not pushed
filename: 'main.js',
publicPath,
module: true,
libraryTarget: 'module',
},
experiments: {
outputModule: true,
},
optimization: {
minimize: isProd ? true : false,
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
Expand Down Expand Up @@ -144,12 +152,24 @@ type DynamicCDNEntry = {

// 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): DynamicCDNEntry | null => {
const moduleDetails = moduleToCdn(packageName, packageVersion, options);
verbose: process.env.VERBOSE ? true : false,
only: [
'react',
'react-dom',
'prop-types',
'material-react-table',
'@emotion/react',
'@emotion/styled',
'gas-client',
],
resolver: (
packageName: string,
version: string,
options: { env: string }
): DynamicCDNEntry | null => {
const moduleDetails = moduleToCdn(packageName, version, options);
const packageSuffix = isProd ? '.min.js' : '.js';

// don't externalize react during development due to issue with react-refresh
Expand All @@ -162,50 +182,34 @@ const DynamicCdnWebpackPluginConfig = {
// "name" should match the package being imported
// "var" is important to get right -- this should be the exposed global. Look up "webpack externals" for info.
switch (packageName) {
case 'react-transition-group':
case 'material-react-table':
return {
name: packageName,
var: 'ReactTransitionGroup',
version: packageVersion,
url: `https://unpkg.com/react-transition-group@${packageVersion}/dist/react-transition-group${packageSuffix}`,
var: 'MaterialReactTable',
version: version,
url: `https://unpkg.com/material-react-table@${version}/dist/index.esm.js`,
};
case '@emotion/react':
return {
name: packageName,
var: 'emotionReact',
version: packageVersion,
url: `https://unpkg.com/@emotion/react@${packageVersion}/dist/emotion-react.umd.min.js`,
version: version,
url: `https://unpkg.com/@emotion/react@${version}/dist/emotion-react.umd${packageSuffix}`,
};
case '@emotion/styled':
return {
name: packageName,
var: 'emotionStyled',
version: packageVersion,
url: `https://unpkg.com/@emotion/styled@${packageVersion}/dist/emotion-styled.umd.min.js`,
};
case 'papaparse': {
return {
name: packageName,
var: 'Papa',
version: packageVersion,
url: `https://unpkg.com/papaparse@${packageVersion}/papaparse.min.js`,
version: version,
url: `https://unpkg.com/@emotion/styled@${version}/dist/emotion-styled.umd${packageSuffix}`,
};
}
// externalize gas-client to keep bundle size even smaller
case 'gas-client':
return {
name: packageName,
var: 'GASClient',
version: packageVersion,
url: `https://unpkg.com/gas-client@${packageVersion}/dist/index.js`,
};
// must include peer dependencies for any custom imports
case '@types/react':
return {
name: packageName,
var: '@types/react',
version: packageVersion,
url: `https://unpkg.com/@types/react@${packageVersion}/index.d.ts`,
version: version,
url: `https://unpkg.com/gas-client@${version}/dist/index.js`,
};
// return defaults/null depending if Dynamic CDN plugin finds package
default:
Expand All @@ -231,15 +235,15 @@ const clientConfigs = clientEntrypoints.map<Configuration>(
template: clientEntrypoint.template,
filename: `${clientEntrypoint.filename}.html`,
inlineSource: '^/.*(js|css)$', // embed all js and css inline, exclude packages from dynamic cdn insertion
scriptLoading: 'blocking',
scriptLoading: 'module',
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),
};
new HtmlInlineScriptPlugin(),
],
} as Configuration;
}
);

Expand Down

0 comments on commit 521ee58

Please sign in to comment.