webpack-plugin-gas-react
v0.1.3
Published
Webpack plugin that deploys React apps to Google Apps Script with automatic code splitting
Maintainers
Readme
webpack-plugin-gas-react
Webpack plugin that deploys React apps to Google Apps Script with automatic code splitting.
The webpack equivalent of
vite-plugin-gas-react. Write a standard React + webpack app. Build. Push to GAS.
Install
npm install webpack-plugin-gas-react --save-devPeer dependencies (install if missing):
npm install webpack html-webpack-plugin --save-devQuick Start
Option 1: createGASWebpackConfig (recommended)
Generates a complete webpack config — just like createGASViteConfig does for Vite:
// webpack.config.mjs
import { createGASWebpackConfig } from 'webpack-plugin-gas-react';
export default await createGASWebpackConfig({
clientRoot: 'src/client',
appTitle: 'My App',
serverEntry: 'src/server/index.ts',
});Option 2: Use GASWebpackPlugin directly
Add the plugin to your existing webpack config:
// webpack.config.mjs
import { GASWebpackPlugin } from 'webpack-plugin-gas-react';
import HtmlWebpackPlugin from 'html-webpack-plugin';
export default {
entry: './src/client/index.tsx',
output: { path: './dist', clean: true },
plugins: [
new HtmlWebpackPlugin({ template: './src/client/index.html' }),
new GASWebpackPlugin({
appTitle: 'My App',
serverEntry: 'src/server/index.ts',
}),
],
// ... rest of config
};Build & Deploy
npx webpack
cd dist && clasp pushHow It Works
React App (Webpack)
├── Client code → webpack build → code-split chunks stored as GAS string variables
└── Server code → esbuild → global functions in Code.js- Entry code is stored as a string variable (
__GAS_ENTRY_CODE__) and loaded at runtime viagetEntryCode() - Lazy chunks (
React.lazy()) are stored as__GAS_CHUNK_page_*__string variables, loaded on demand viagetPage(name) - Server entry is bundled via esbuild with exports hoisted to global scope
- HTML is transformed — webpack script tags are removed and replaced with a GAS chunk loader
Code.jsis generated withdoGet(),getPage(),getEntryCode(), and your server functionsappsscript.jsonis generated automatically
Options
createGASWebpackConfig(options)
| Option | Type | Default | Description |
|---|---|---|---|
| clientRoot | string | "src/client" | Root directory of client code |
| outDir | string | "dist" | Output directory |
| devServerPort | number | 3001 | Port for the gas-react-core dev server proxy |
| devPort | number | 8080 | Webpack dev server port |
| aliases | Record<string, string> | {} | Path aliases (e.g. { "@": "src" }) |
| plugins | unknown[] | [] | Extra webpack plugins |
| appTitle | string | "GAS App" | Title for the GAS web app |
| serverEntry | string | — | Path to server entry (e.g. "src/server/index.ts") |
| webpack | object | {} | Additional webpack config overrides |
GASWebpackPlugin(options)
| Option | Type | Default | Description |
|---|---|---|---|
| pagePrefix | string | "page_" | Prefix for lazy-loaded page chunk names |
| appTitle | string | "GAS App" | Title for the web app |
| serverEntry | string | — | Path to server entry file |
Development Mode
Set GAS_LOCAL=true to run in dev mode:
GAS_LOCAL=true npx webpack serveWhen createGASWebpackConfig detects dev mode:
- Runs a normal webpack dev server (HMR, source maps)
- Sets
window.__GAS_DEV_MODE__ = truesogas-react-core/clientroutes calls to your local dev server - Does not apply GAS transformations
Comparison with vite-plugin-gas-react
Both plugins produce identical GAS output. Choose based on your bundler:
| Feature | vite-plugin-gas-react | webpack-plugin-gas-react |
|---|---|---|
| Bundler | Vite | Webpack 5+ |
| Code splitting | ✅ | ✅ |
| Server bundling | ✅ (esbuild) | ✅ (esbuild) |
| HTML transform | ✅ | ✅ |
| Dev mode | ✅ | ✅ |
| appsscript.json | ✅ | ✅ |
| Config helper | createGASViteConfig | createGASWebpackConfig |
Full Example
webpack.config.mjs:
import { createGASWebpackConfig } from 'webpack-plugin-gas-react';
export default await createGASWebpackConfig({
clientRoot: 'src/client',
appTitle: 'My App',
serverEntry: 'src/server/index.ts',
});Server (src/server/index.ts):
import { DataStore, withCache, removeFromCache } from 'gas-react-core/server';
export function getUsers() {
return withCache({
cacheKey: 'all-users',
fetchFunction: () => DataStore.getAll('users'),
});
}
export function createUser(data: Record<string, unknown>) {
DataStore.insert('users', data);
removeFromCache('all-users');
return { success: true };
}Client (src/services/user-service.ts):
import { executeFn } from 'gas-react-core/client';
export const getUsers = () => executeFn<User[]>('getUsers');
export const createUser = (data: User) => executeFn('createUser', [data]);Build & deploy:
npx webpack
cd dist && clasp pushLicense
MIT
