@gasboost/vite 0.1.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +509 -136
- package/dist/build.d.ts +3 -0
- package/dist/dev.d.ts +3 -0
- package/dist/gasboost.d.ts +6 -1
- package/dist/globals.d.ts +2 -2
- package/dist/index.js +158 -102
- package/dist/loadAppsScript.d.ts +4 -0
- package/dist/runtime.d.ts +3 -0
- package/package.json +6 -2
- package/dist/analyzer.d.ts +0 -6
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 gasboost
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
# @gasboost/vite
|
|
2
2
|
|
|
3
|
-
`@gasboost/app`
|
|
3
|
+
`@gasboost/app` で構築した Google Apps Script アプリケーションを、Vite でビルド・ローカル開発するためのプラグインです。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`@gasboost/vite` は用途ごとに2つの Vite Plugin を提供します。
|
|
6
|
+
|
|
7
|
+
- `build` — Google Apps Script 向けの production build
|
|
8
|
+
- `dev` — ローカル開発時の RPC 実行
|
|
6
9
|
|
|
7
10
|
## インストール
|
|
8
11
|
|
|
@@ -18,119 +21,175 @@ npm install @gasboost/app
|
|
|
18
21
|
npm install -D @gasboost/vite vite
|
|
19
22
|
```
|
|
20
23
|
|
|
21
|
-
##
|
|
24
|
+
## Quick Start
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
まず `@gasboost/app` でバックエンドを定義します。
|
|
24
27
|
|
|
25
28
|
```ts
|
|
26
|
-
// src/
|
|
29
|
+
// src/server.ts
|
|
27
30
|
|
|
28
31
|
import { AppsScript } from "@gasboost/app";
|
|
29
32
|
|
|
30
33
|
const app = new AppsScript()
|
|
31
|
-
.get((
|
|
34
|
+
.get(() => {
|
|
32
35
|
return HtmlService.createHtmlOutput("Hello");
|
|
33
36
|
})
|
|
34
37
|
.post((request) => {
|
|
35
38
|
return ContentService.createTextOutput(request.text());
|
|
36
39
|
})
|
|
37
|
-
.call("sum", (a: number, b: number) => a + b)
|
|
40
|
+
.call("sum", (a: number, b: number) => a + b)
|
|
41
|
+
.call("getUser", async (id: string) => ({
|
|
42
|
+
id,
|
|
43
|
+
name: "Taro",
|
|
44
|
+
}));
|
|
38
45
|
|
|
39
46
|
export default app;
|
|
40
47
|
```
|
|
41
48
|
|
|
42
|
-
|
|
49
|
+
`gasboost()` から `build` と `dev` を取得し、1つの `vite.config.ts` の中で mode に応じて使い分けます。
|
|
50
|
+
|
|
51
|
+
frontend と backend は成果物と build graph が異なるため、同時に1つの Vite build へ混在させません。
|
|
43
52
|
|
|
44
53
|
```ts
|
|
45
54
|
// vite.config.ts
|
|
46
55
|
|
|
56
|
+
import react from "@vitejs/plugin-react";
|
|
47
57
|
import { defineConfig } from "vite";
|
|
58
|
+
import { viteSingleFile } from "vite-plugin-singlefile";
|
|
48
59
|
import { gasboost } from "@gasboost/vite";
|
|
49
60
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
entry: "src/main.ts",
|
|
54
|
-
}),
|
|
55
|
-
],
|
|
61
|
+
const { build, dev } = gasboost({
|
|
62
|
+
entry: "src/server.ts",
|
|
63
|
+
envDir: ".env",
|
|
56
64
|
});
|
|
57
|
-
```
|
|
58
65
|
|
|
59
|
-
|
|
66
|
+
export default defineConfig(({ mode }) => {
|
|
67
|
+
if (mode === "server") {
|
|
68
|
+
return {
|
|
69
|
+
plugins: [build],
|
|
70
|
+
build: {
|
|
71
|
+
outDir: "dist",
|
|
72
|
+
emptyOutDir: false,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
plugins: [react(), viteSingleFile(), dev],
|
|
79
|
+
build: {
|
|
80
|
+
outDir: "dist",
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
```
|
|
60
85
|
|
|
61
|
-
|
|
62
|
-
|
|
86
|
+
この例では、frontend build と backend build を mode で分離します。
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"scripts": {
|
|
91
|
+
"dev": "vite",
|
|
92
|
+
"build:client": "vite build --mode client",
|
|
93
|
+
"build:server": "vite build --mode server",
|
|
94
|
+
"build": "pnpm build:client && pnpm build:server"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
63
97
|
```
|
|
64
98
|
|
|
65
|
-
|
|
99
|
+
```text
|
|
100
|
+
vite
|
|
101
|
+
↓
|
|
102
|
+
gasboost:dev
|
|
66
103
|
|
|
67
|
-
|
|
104
|
+
vite build --mode client
|
|
105
|
+
↓
|
|
106
|
+
frontend build
|
|
68
107
|
|
|
69
|
-
|
|
108
|
+
vite build --mode server
|
|
109
|
+
↓
|
|
110
|
+
gasboost:build
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
frontend 側の React、single-file 化などの設定は利用側プロジェクトの責務です。
|
|
70
114
|
|
|
71
|
-
|
|
115
|
+
## gasboost()
|
|
72
116
|
|
|
73
117
|
```ts
|
|
74
|
-
gasboost({
|
|
75
|
-
entry: "src/
|
|
118
|
+
const { build, dev } = gasboost({
|
|
119
|
+
entry: "src/server.ts",
|
|
120
|
+
envDir: "config",
|
|
76
121
|
});
|
|
77
122
|
```
|
|
78
123
|
|
|
79
|
-
|
|
124
|
+
戻り値:
|
|
80
125
|
|
|
81
126
|
```ts
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
127
|
+
{
|
|
128
|
+
build: Plugin;
|
|
129
|
+
dev: Plugin;
|
|
130
|
+
}
|
|
85
131
|
```
|
|
86
132
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
```ts
|
|
90
|
-
const app = new AppsScript()
|
|
91
|
-
.get(...)
|
|
92
|
-
.post(...)
|
|
93
|
-
.call("getUser", ...);
|
|
133
|
+
### `entry`
|
|
94
134
|
|
|
95
|
-
|
|
96
|
-
```
|
|
135
|
+
必須です。
|
|
97
136
|
|
|
98
|
-
|
|
137
|
+
`AppsScript` を定義して default export している entry file を指定します。
|
|
99
138
|
|
|
100
139
|
```ts
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
app.call("getUser", ...);
|
|
105
|
-
|
|
106
|
-
export default app;
|
|
140
|
+
gasboost({
|
|
141
|
+
entry: "src/server.ts",
|
|
142
|
+
});
|
|
107
143
|
```
|
|
108
144
|
|
|
109
145
|
### `envDir`
|
|
110
146
|
|
|
111
147
|
任意です。
|
|
112
148
|
|
|
113
|
-
Vite が環境変数ファイルを読み込むディレクトリを指定します。
|
|
149
|
+
build 時に Vite が環境変数ファイルを読み込むディレクトリを指定します。
|
|
114
150
|
|
|
115
151
|
```ts
|
|
116
152
|
gasboost({
|
|
117
|
-
entry: "src/
|
|
153
|
+
entry: "src/server.ts",
|
|
118
154
|
envDir: "config",
|
|
119
155
|
});
|
|
120
156
|
```
|
|
121
157
|
|
|
122
|
-
|
|
158
|
+
---
|
|
123
159
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
160
|
+
# Build Plugin
|
|
161
|
+
|
|
162
|
+
`build` は `vite build` のときだけ動作し、GAS backend build を担当します。
|
|
163
|
+
|
|
164
|
+
frontend / backend を同じ `vite.config.ts` で扱う場合は、server 用 mode のときだけ `plugins` に含めてください。
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
const { build } = gasboost({
|
|
168
|
+
entry: "src/server.ts",
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
export default defineConfig(({ mode }) => {
|
|
172
|
+
if (mode === "server") {
|
|
173
|
+
return {
|
|
174
|
+
plugins: [build],
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
plugins: [],
|
|
180
|
+
};
|
|
181
|
+
});
|
|
129
182
|
```
|
|
130
183
|
|
|
131
|
-
|
|
184
|
+
`build` plugin は次の処理を担当します。
|
|
132
185
|
|
|
133
|
-
|
|
186
|
+
- entry file の静的解析
|
|
187
|
+
- `AppsScript` に登録された GET / POST / RPC の検出
|
|
188
|
+
- GAS が認識するグローバル関数宣言の生成
|
|
189
|
+
- GAS 向け Vite build configuration
|
|
190
|
+
- 環境変数の読み込み
|
|
191
|
+
|
|
192
|
+
## グローバル関数の生成
|
|
134
193
|
|
|
135
194
|
例えば次のアプリケーションを定義した場合:
|
|
136
195
|
|
|
@@ -144,7 +203,7 @@ const app = new AppsScript()
|
|
|
144
203
|
export default app;
|
|
145
204
|
```
|
|
146
205
|
|
|
147
|
-
|
|
206
|
+
build plugin は GAS が認識するためのグローバル関数宣言を生成します。
|
|
148
207
|
|
|
149
208
|
```js
|
|
150
209
|
function doGet() {}
|
|
@@ -153,56 +212,51 @@ function getUser() {}
|
|
|
153
212
|
function sum() {}
|
|
154
213
|
```
|
|
155
214
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
実際の dispatch 処理は行いません。
|
|
159
|
-
|
|
160
|
-
ハンドラの実体は `@gasboost/app` がランタイム上で登録します。
|
|
215
|
+
これらは関数名を Google Apps Script に認識させるための宣言です。
|
|
161
216
|
|
|
162
|
-
|
|
217
|
+
実際のハンドラ登録と dispatch は `@gasboost/app` がランタイム上で行います。
|
|
163
218
|
|
|
164
219
|
```text
|
|
165
|
-
@gasboost/app
|
|
166
|
-
runtime registration
|
|
167
|
-
handler dispatch
|
|
168
|
-
globalThis implementation
|
|
169
|
-
|
|
170
220
|
@gasboost/vite
|
|
171
221
|
static analysis
|
|
172
|
-
GAS build configuration
|
|
173
222
|
global function declarations
|
|
223
|
+
↓
|
|
224
|
+
@gasboost/app
|
|
225
|
+
runtime registration
|
|
226
|
+
dispatch
|
|
174
227
|
```
|
|
175
228
|
|
|
176
229
|
## 静的解析
|
|
177
230
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
対象となる `AppsScript` インスタンスに対する登録を検出します。
|
|
231
|
+
entry file には1つの `AppsScript` インスタンスを定義し、default export します。
|
|
181
232
|
|
|
182
233
|
```ts
|
|
234
|
+
const app = new AppsScript();
|
|
235
|
+
|
|
183
236
|
app.get(...);
|
|
184
|
-
app.post(...);
|
|
185
237
|
app.call("getUser", ...);
|
|
238
|
+
|
|
239
|
+
export default app;
|
|
186
240
|
```
|
|
187
241
|
|
|
188
|
-
|
|
242
|
+
チェーン形式にも対応しています。
|
|
189
243
|
|
|
190
244
|
```ts
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
245
|
+
const app = new AppsScript()
|
|
246
|
+
.get(...)
|
|
247
|
+
.post(...)
|
|
248
|
+
.call("getUser", ...);
|
|
194
249
|
|
|
195
|
-
|
|
250
|
+
export default app;
|
|
251
|
+
```
|
|
196
252
|
|
|
197
253
|
RPC 名は文字列リテラルで指定する必要があります。
|
|
198
254
|
|
|
199
|
-
対応:
|
|
200
|
-
|
|
201
255
|
```ts
|
|
202
256
|
app.call("getUser", handler);
|
|
203
257
|
```
|
|
204
258
|
|
|
205
|
-
|
|
259
|
+
次のような動的な名前は静的解析の対象外です。
|
|
206
260
|
|
|
207
261
|
```ts
|
|
208
262
|
const name = "getUser";
|
|
@@ -210,123 +264,442 @@ const name = "getUser";
|
|
|
210
264
|
app.call(name, handler);
|
|
211
265
|
```
|
|
212
266
|
|
|
213
|
-
|
|
267
|
+
build 時に GAS のグローバル関数名を確定する必要があるためです。
|
|
214
268
|
|
|
215
|
-
|
|
269
|
+
## 検証
|
|
216
270
|
|
|
217
|
-
|
|
271
|
+
静的解析時には、曖昧なアプリケーション定義をエラーとして扱います。
|
|
218
272
|
|
|
219
273
|
- GET ハンドラの重複
|
|
220
274
|
- POST ハンドラの重複
|
|
221
275
|
- RPC 名の重複
|
|
222
|
-
- entry
|
|
223
|
-
|
|
224
|
-
`AppsScript` インスタンスは default export されている必要があります。
|
|
276
|
+
- entry 内の複数 `AppsScript` インスタンス
|
|
277
|
+
- default export されていない `AppsScript`
|
|
225
278
|
|
|
226
|
-
## GAS
|
|
279
|
+
## GAS 向け build configuration
|
|
227
280
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
現在は以下の設定を利用します。
|
|
281
|
+
現在の build 設定:
|
|
231
282
|
|
|
232
283
|
- target: ECMAScript 2019
|
|
233
284
|
- output format: CommonJS
|
|
234
285
|
- output directory: `dist`
|
|
235
|
-
- `entry`
|
|
236
|
-
|
|
237
|
-
利用側の Vite config で GAS 固有の build setting を重複して定義する必要はありません。
|
|
286
|
+
- `entry` を build input として利用
|
|
238
287
|
|
|
239
288
|
## 環境変数
|
|
240
289
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
例えば:
|
|
290
|
+
Vite 標準の環境変数機構を利用します。
|
|
244
291
|
|
|
245
292
|
```text
|
|
246
|
-
config
|
|
293
|
+
config/
|
|
294
|
+
├── .env
|
|
295
|
+
├── .env.development
|
|
296
|
+
└── .env.production
|
|
247
297
|
```
|
|
248
298
|
|
|
249
|
-
```
|
|
250
|
-
|
|
299
|
+
```ts
|
|
300
|
+
const { build } = gasboost({
|
|
301
|
+
entry: "src/server.ts",
|
|
302
|
+
envDir: "config",
|
|
303
|
+
});
|
|
251
304
|
```
|
|
252
305
|
|
|
253
|
-
|
|
306
|
+
アプリケーションでは通常の Vite と同様に参照できます。
|
|
254
307
|
|
|
255
308
|
```ts
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
309
|
+
const apiUrl = import.meta.env.VITE_API_URL;
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
# Dev Plugin
|
|
315
|
+
|
|
316
|
+
`dev` は Vite Dev Server 上でのみ動作します。
|
|
317
|
+
|
|
318
|
+
frontend の開発用 Vite config に追加して利用します。
|
|
319
|
+
|
|
320
|
+
```ts
|
|
321
|
+
const { dev } = gasboost({
|
|
322
|
+
entry: "src/server.ts",
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
export default defineConfig({
|
|
326
|
+
plugins: [dev],
|
|
259
327
|
});
|
|
260
328
|
```
|
|
261
329
|
|
|
262
|
-
|
|
330
|
+
`dev` plugin は、GAS にデプロイしなくてもローカル環境から `AppsScript` の RPC を実行できるエンドポイントを Vite Dev Server に追加します。
|
|
331
|
+
|
|
332
|
+
## Local RPC
|
|
333
|
+
|
|
334
|
+
ローカル RPC のエンドポイントは次の形式です。
|
|
335
|
+
|
|
336
|
+
```text
|
|
337
|
+
POST /__gasboost/{rpcName}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
例えば、
|
|
263
341
|
|
|
264
342
|
```ts
|
|
265
|
-
const
|
|
343
|
+
const app = new AppsScript().call("sum", (a: number, b: number) => a + b);
|
|
344
|
+
|
|
345
|
+
export default app;
|
|
266
346
|
```
|
|
267
347
|
|
|
268
|
-
|
|
348
|
+
に対して、
|
|
269
349
|
|
|
270
|
-
```
|
|
271
|
-
|
|
350
|
+
```http
|
|
351
|
+
POST /__gasboost/sum
|
|
352
|
+
Content-Type: application/json
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
```json
|
|
356
|
+
{
|
|
357
|
+
"args": [1, 2]
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
を送信すると、内部では次の dispatch が実行されます。
|
|
362
|
+
|
|
363
|
+
```ts
|
|
364
|
+
app.dispatch("sum", 1, 2);
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
レスポンス:
|
|
368
|
+
|
|
369
|
+
```json
|
|
370
|
+
3
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
## RPC Request
|
|
374
|
+
|
|
375
|
+
Request Body は次の形式です。
|
|
376
|
+
|
|
377
|
+
```ts
|
|
378
|
+
{
|
|
379
|
+
args: unknown[];
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
例えば複数の引数を持つ RPC:
|
|
384
|
+
|
|
385
|
+
```ts
|
|
386
|
+
app.call(
|
|
387
|
+
"example",
|
|
388
|
+
(id: number, name: string, active: boolean, options: { value: number }) => {
|
|
389
|
+
// ...
|
|
390
|
+
},
|
|
391
|
+
);
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
に対して、
|
|
395
|
+
|
|
396
|
+
```json
|
|
397
|
+
{
|
|
398
|
+
"args": [
|
|
399
|
+
1,
|
|
400
|
+
"Taro",
|
|
401
|
+
true,
|
|
402
|
+
{
|
|
403
|
+
"value": 4
|
|
404
|
+
}
|
|
405
|
+
]
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
のように送信できます。
|
|
410
|
+
|
|
411
|
+
### 引数なし RPC
|
|
412
|
+
|
|
413
|
+
Request Body が空の場合は、引数なし RPC として扱われます。
|
|
414
|
+
|
|
415
|
+
```http
|
|
416
|
+
POST /__gasboost/noArgs
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
内部では次のように dispatch されます。
|
|
420
|
+
|
|
421
|
+
```ts
|
|
422
|
+
app.dispatch("noArgs");
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
明示的に送る場合は次でも構いません。
|
|
426
|
+
|
|
427
|
+
```json
|
|
428
|
+
{
|
|
429
|
+
"args": []
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
## RPC Response
|
|
434
|
+
|
|
435
|
+
`@gasboost/app` の `dispatch()` が返す `AppsScriptResponse.contents` を、そのまま HTTP Response Body として返します。
|
|
436
|
+
|
|
437
|
+
例えば、
|
|
438
|
+
|
|
439
|
+
```ts
|
|
440
|
+
app.call("getUser", () => ({
|
|
441
|
+
id: 1,
|
|
442
|
+
name: "Taro",
|
|
443
|
+
}));
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
に対するレスポンスは:
|
|
447
|
+
|
|
448
|
+
```json
|
|
449
|
+
{
|
|
450
|
+
"id": 1,
|
|
451
|
+
"name": "Taro"
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
となります。
|
|
456
|
+
|
|
457
|
+
Response の Content-Type は:
|
|
458
|
+
|
|
459
|
+
```text
|
|
460
|
+
application/json; charset=utf-8
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
です。
|
|
464
|
+
|
|
465
|
+
## Async RPC
|
|
466
|
+
|
|
467
|
+
非同期 RPC にも対応しています。
|
|
468
|
+
|
|
469
|
+
```ts
|
|
470
|
+
app.call("loadUser", async (id: string) => {
|
|
471
|
+
const user = await loadUser(id);
|
|
472
|
+
|
|
473
|
+
return user;
|
|
474
|
+
});
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
dev plugin は `dispatch()` の完了を待ってからレスポンスを返します。
|
|
478
|
+
|
|
479
|
+
## 開発中の module loading
|
|
480
|
+
|
|
481
|
+
RPC リクエストごとに、指定された `entry` を Vite の `ssrLoadModule()` で読み込みます。
|
|
482
|
+
|
|
483
|
+
```text
|
|
484
|
+
POST /__gasboost/sum
|
|
485
|
+
↓
|
|
486
|
+
ssrLoadModule("src/server.ts")
|
|
487
|
+
↓
|
|
488
|
+
AppsScript.dispatch("sum", ...)
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
そのため、Vite Dev Server 上の最新のサーバーコードを利用して RPC を実行できます。
|
|
492
|
+
|
|
493
|
+
## Error Response
|
|
494
|
+
|
|
495
|
+
### 不正な Request Body
|
|
496
|
+
|
|
497
|
+
JSON として不正な body や、`args` が配列でない body は `400` を返します。
|
|
498
|
+
|
|
499
|
+
```json
|
|
500
|
+
{
|
|
501
|
+
"args": "invalid"
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
レスポンス例:
|
|
506
|
+
|
|
507
|
+
```json
|
|
508
|
+
{
|
|
509
|
+
"error": {
|
|
510
|
+
"name": "InvalidRpcRequestError",
|
|
511
|
+
"message": "Invalid RPC request body. Expected { args: unknown[] }."
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
JSON 自体が不正な場合も `400` です。
|
|
517
|
+
|
|
518
|
+
### POST 以外
|
|
519
|
+
|
|
520
|
+
Local RPC endpoint は POST のみ受け付けます。
|
|
521
|
+
|
|
522
|
+
```http
|
|
523
|
+
GET /__gasboost/sum
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
は `405` になります。
|
|
527
|
+
|
|
528
|
+
```json
|
|
529
|
+
{
|
|
530
|
+
"error": {
|
|
531
|
+
"name": "MethodNotAllowedError",
|
|
532
|
+
"message": "Only POST is allowed."
|
|
533
|
+
}
|
|
534
|
+
}
|
|
272
535
|
```
|
|
273
536
|
|
|
274
|
-
|
|
537
|
+
### 未登録 RPC
|
|
538
|
+
|
|
539
|
+
存在しない RPC を呼び出した場合は `500` を返します。
|
|
275
540
|
|
|
276
541
|
```text
|
|
277
|
-
|
|
542
|
+
POST /__gasboost/unknown
|
|
278
543
|
```
|
|
279
544
|
|
|
280
|
-
|
|
545
|
+
```json
|
|
546
|
+
{
|
|
547
|
+
"error": {
|
|
548
|
+
"name": "Error",
|
|
549
|
+
"message": "Function unknown is not registered."
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
```
|
|
281
553
|
|
|
282
|
-
|
|
554
|
+
### Handler Error
|
|
283
555
|
|
|
284
|
-
|
|
556
|
+
RPC handler 内で例外が発生した場合も `500` として JSON で返されます。
|
|
285
557
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
558
|
+
```json
|
|
559
|
+
{
|
|
560
|
+
"error": {
|
|
561
|
+
"name": "TypeError",
|
|
562
|
+
"message": "handler failed"
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
## Local RPC の対象 path
|
|
290
568
|
|
|
291
|
-
|
|
569
|
+
次の形式だけを RPC として扱います。
|
|
292
570
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
571
|
+
```text
|
|
572
|
+
/__gasboost/{rpcName}
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
例えば以下は対象です。
|
|
576
|
+
|
|
577
|
+
```text
|
|
578
|
+
/__gasboost/getUser
|
|
579
|
+
/__gasboost/sum
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
一方、次のような path は RPC として扱いません。
|
|
583
|
+
|
|
584
|
+
```text
|
|
585
|
+
/__gasboost/
|
|
586
|
+
/__gasboost/foo/bar
|
|
587
|
+
/api/users
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
通常の Vite middleware chain に処理を渡します。
|
|
591
|
+
|
|
592
|
+
query string が付いていても RPC 名は正しく解決されます。
|
|
593
|
+
|
|
594
|
+
```text
|
|
595
|
+
/__gasboost/hello?foo=bar
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
URL encoded な RPC 名も decode されます。
|
|
599
|
+
|
|
600
|
+
```text
|
|
601
|
+
/__gasboost/hello%20world
|
|
602
|
+
```
|
|
298
603
|
|
|
299
|
-
|
|
604
|
+
---
|
|
300
605
|
|
|
301
|
-
|
|
606
|
+
# build と dev の責務
|
|
302
607
|
|
|
303
|
-
|
|
608
|
+
```text
|
|
609
|
+
gasboost()
|
|
610
|
+
│
|
|
611
|
+
├─ build
|
|
612
|
+
│ ├─ AppsScript の静的解析
|
|
613
|
+
│ ├─ GAS グローバル関数生成
|
|
614
|
+
│ ├─ GAS 向け build config
|
|
615
|
+
│ └─ backend production build
|
|
616
|
+
│
|
|
617
|
+
└─ dev
|
|
618
|
+
├─ Vite Dev Server middleware
|
|
619
|
+
├─ Local RPC endpoint
|
|
620
|
+
├─ entry の ssrLoadModule
|
|
621
|
+
└─ AppsScript.dispatch
|
|
622
|
+
```
|
|
304
623
|
|
|
305
|
-
|
|
624
|
+
frontend と backend を1つの `vite.config.ts` で扱う場合は、mode で分岐します。
|
|
306
625
|
|
|
307
626
|
```ts
|
|
308
|
-
const
|
|
309
|
-
|
|
627
|
+
const { build, dev } = gasboost({
|
|
628
|
+
entry: "src/server.ts",
|
|
629
|
+
});
|
|
310
630
|
|
|
311
|
-
export default
|
|
631
|
+
export default defineConfig(({ mode }) => {
|
|
632
|
+
if (mode === "server") {
|
|
633
|
+
return {
|
|
634
|
+
plugins: [build],
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
return {
|
|
639
|
+
plugins: [dev],
|
|
640
|
+
};
|
|
641
|
+
});
|
|
312
642
|
```
|
|
313
643
|
|
|
314
|
-
|
|
644
|
+
`build` を通常の frontend build に含めると、server entry が Vite の build input になるため、frontend と backend の build は分離してください。
|
|
645
|
+
|
|
646
|
+
---
|
|
647
|
+
|
|
648
|
+
## GAS ランタイム
|
|
649
|
+
|
|
650
|
+
`@gasboost/vite` は、build 時と local RPC 実行時に server entry を実際に評価します。
|
|
651
|
+
|
|
652
|
+
一般的な GAS API は、デフォルトのローカルランタイムから提供されます。
|
|
315
653
|
|
|
316
654
|
```ts
|
|
317
|
-
|
|
655
|
+
import { gasboost } from "@gasboost/vite";
|
|
656
|
+
|
|
657
|
+
export default gasboost({
|
|
658
|
+
entry: "./src/server.ts",
|
|
659
|
+
});
|
|
318
660
|
```
|
|
319
661
|
|
|
320
|
-
|
|
662
|
+
entry の初期化時に追加の GAS API が必要な場合は、`runtime` から差し込めます。
|
|
321
663
|
|
|
322
664
|
```ts
|
|
323
|
-
import {
|
|
665
|
+
import { SpreadsheetAppStub } from "@gasboost/sheetorm";
|
|
666
|
+
import { gasboost } from "@gasboost/vite";
|
|
324
667
|
|
|
325
|
-
|
|
668
|
+
export default gasboost({
|
|
669
|
+
entry: "./src/server.ts",
|
|
670
|
+
runtime: {
|
|
671
|
+
SpreadsheetApp: SpreadsheetAppStub,
|
|
672
|
+
},
|
|
673
|
+
});
|
|
326
674
|
```
|
|
327
675
|
|
|
328
|
-
|
|
676
|
+
`runtime` に渡した値は、デフォルトのローカルランタイムを上書きします。
|
|
677
|
+
|
|
678
|
+
このランタイムは build 時の entry 評価と、local RPC 実行時の両方で利用されます。
|
|
679
|
+
|
|
680
|
+
基本的には、module 初期化時に必要な API だけを差し込み、実際の GAS API 呼び出しは handler 実行時まで遅延させることを推奨します。
|
|
681
|
+
|
|
682
|
+
## ランタイム解析
|
|
683
|
+
|
|
684
|
+
GET / POST / RPC の登録状態は、entry ファイルを静的解析するのではなく、実際に評価された `AppsScript` インスタンスから取得します。
|
|
685
|
+
|
|
686
|
+
そのため、import 先、ヘルパー関数、loop、`AppsScript.calls()` 経由の登録にも対応できます。
|
|
687
|
+
|
|
688
|
+
```ts
|
|
689
|
+
const app = new AppsScript();
|
|
690
|
+
|
|
691
|
+
for (const [name, handler] of Object.entries(handlers)) {
|
|
692
|
+
app.call(name, handler);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
export default app;
|
|
696
|
+
```
|
|
329
697
|
|
|
330
698
|
## 関連パッケージ
|
|
331
699
|
|
|
332
|
-
|
|
700
|
+
- `@gasboost/app` — GAS バックエンドランタイムと RPC 定義
|
|
701
|
+
- `@gasboost/client` — フロントエンド側の型安全 RPC クライアント
|
|
702
|
+
|
|
703
|
+
## License
|
|
704
|
+
|
|
705
|
+
MIT
|
package/dist/build.d.ts
ADDED
package/dist/dev.d.ts
ADDED
package/dist/gasboost.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
|
+
export type GasRuntime = Readonly<Record<string, unknown>>;
|
|
2
3
|
export interface GasboostOptions {
|
|
3
4
|
entry: string;
|
|
4
5
|
envDir?: string;
|
|
6
|
+
runtime?: GasRuntime;
|
|
5
7
|
}
|
|
6
|
-
export declare function gasboost(options: GasboostOptions):
|
|
8
|
+
export declare function gasboost(options: GasboostOptions): {
|
|
9
|
+
build: Plugin;
|
|
10
|
+
dev: Plugin;
|
|
11
|
+
};
|
package/dist/globals.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function createGlobalCode(analysis:
|
|
1
|
+
import type { AppsScriptDescription } from "@gasboost/app";
|
|
2
|
+
export declare function createGlobalCode(analysis: AppsScriptDescription): string;
|
package/dist/index.js
CHANGED
|
@@ -1,91 +1,12 @@
|
|
|
1
|
-
import e from "node:
|
|
2
|
-
import t from "
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { API as l } from "typescript/unstable/sync";
|
|
6
|
-
//#region src/analyzer.ts
|
|
7
|
-
function u(r) {
|
|
8
|
-
let i = t.resolve(r);
|
|
9
|
-
if (!e.existsSync(i)) throw Error(`Entry file not found: ${i}`);
|
|
10
|
-
let s = d(i, e.readFileSync(i, "utf8")), c = f(s);
|
|
11
|
-
if (c.length === 0) throw Error("AppsScript instance not found.");
|
|
12
|
-
if (c.length > 1) throw Error("Multiple AppsScript instances found in entry.");
|
|
13
|
-
let l = c[0];
|
|
14
|
-
g(s, l);
|
|
15
|
-
let u = {
|
|
16
|
-
hasGet: !1,
|
|
17
|
-
hasPost: !1,
|
|
18
|
-
calls: []
|
|
19
|
-
}, p = /* @__PURE__ */ new Set();
|
|
20
|
-
function m(e) {
|
|
21
|
-
if (!a(e.expression)) return;
|
|
22
|
-
let t = e.expression, n = t.name.text;
|
|
23
|
-
if (!h(t.expression, l)) return;
|
|
24
|
-
if (n === "get") {
|
|
25
|
-
if (u.hasGet) throw Error("Duplicate GET handler registration.");
|
|
26
|
-
u.hasGet = !0;
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
if (n === "post") {
|
|
30
|
-
if (u.hasPost) throw Error("Duplicate POST handler registration.");
|
|
31
|
-
u.hasPost = !0;
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
if (n !== "call") return;
|
|
35
|
-
let r = e.arguments[0];
|
|
36
|
-
if (!r) throw Error(".call() requires a function name.");
|
|
37
|
-
if (!o(r)) throw Error(".call() function name must be a string literal.");
|
|
38
|
-
if (p.has(r.text)) throw Error(`Duplicate RPC registration: "${r.text}".`);
|
|
39
|
-
p.add(r.text), u.calls.unshift(r.text);
|
|
40
|
-
}
|
|
41
|
-
function _(e) {
|
|
42
|
-
n(e) && m(e), e.forEachChild(_);
|
|
43
|
-
}
|
|
44
|
-
return _(s), u;
|
|
45
|
-
}
|
|
46
|
-
function d(e, t) {
|
|
47
|
-
let n = "/entry.ts", r = "/tsconfig.json", i = c({
|
|
48
|
-
[r]: JSON.stringify({ files: [n] }),
|
|
49
|
-
[n]: t
|
|
50
|
-
}), a = new l({
|
|
51
|
-
cwd: "/",
|
|
52
|
-
fs: i
|
|
53
|
-
}).updateSnapshot({ openProject: r }).getProject(r);
|
|
54
|
-
if (!a) throw Error("Failed to create TypeScript project.");
|
|
55
|
-
let o = a.program.getSourceFile(n);
|
|
56
|
-
if (!o) throw Error(`Failed to parse entry: ${e}`);
|
|
57
|
-
return o;
|
|
58
|
-
}
|
|
59
|
-
function f(e) {
|
|
60
|
-
let t = [];
|
|
61
|
-
function n(e) {
|
|
62
|
-
s(e) && p(e) && t.push(e.name.text), e.forEachChild(n);
|
|
63
|
-
}
|
|
64
|
-
return n(e), t;
|
|
65
|
-
}
|
|
66
|
-
function p(e) {
|
|
67
|
-
return !r(e.name) || !e.initializer ? !1 : m(e.initializer);
|
|
68
|
-
}
|
|
69
|
-
function m(e) {
|
|
70
|
-
return i(e) && r(e.expression) && e.expression.text === "AppsScript" ? !0 : n(e) && a(e.expression) ? m(e.expression.expression) : !1;
|
|
71
|
-
}
|
|
72
|
-
function h(e, t) {
|
|
73
|
-
return r(e) && e.text === t || i(e) && r(e.expression) && e.expression.text === "AppsScript" ? !0 : n(e) && a(e.expression) ? h(e.expression.expression, t) : !1;
|
|
74
|
-
}
|
|
75
|
-
function g(e, t) {
|
|
76
|
-
let n = !1;
|
|
77
|
-
for (let r of e.statements) if (r.getText() === `export default ${t};`) {
|
|
78
|
-
n = !0;
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
|
-
if (!n) throw Error("AppsScript instance must be default exported.");
|
|
82
|
-
}
|
|
83
|
-
//#endregion
|
|
1
|
+
import e from "node:path";
|
|
2
|
+
import { createServer as t, isRunnableDevEnvironment as n } from "vite";
|
|
3
|
+
import { InMemoryCacheService as r, InMemoryContext as i, InMemoryPropertiesService as a, InMemorySession as o, SecurityPolicy as s } from "@gasboost/fake-core";
|
|
4
|
+
import { NodeUtilities as c } from "@gasboost/fake-node";
|
|
84
5
|
//#region src/config.ts
|
|
85
|
-
function
|
|
86
|
-
let n =
|
|
6
|
+
function l(t) {
|
|
7
|
+
let n = e.resolve(t.entry);
|
|
87
8
|
return {
|
|
88
|
-
envDir:
|
|
9
|
+
envDir: t.envDir,
|
|
89
10
|
build: {
|
|
90
11
|
target: "es2019",
|
|
91
12
|
outDir: "dist",
|
|
@@ -94,7 +15,7 @@ function _(e) {
|
|
|
94
15
|
input: n,
|
|
95
16
|
output: {
|
|
96
17
|
format: "cjs",
|
|
97
|
-
entryFileNames:
|
|
18
|
+
entryFileNames: e.basename(n, e.extname(n)) + ".js"
|
|
98
19
|
}
|
|
99
20
|
}
|
|
100
21
|
}
|
|
@@ -102,34 +23,169 @@ function _(e) {
|
|
|
102
23
|
}
|
|
103
24
|
//#endregion
|
|
104
25
|
//#region src/globals.ts
|
|
105
|
-
var
|
|
106
|
-
function
|
|
107
|
-
if (
|
|
26
|
+
var u = /* @__PURE__ */ new Set(["doGet", "doPost"]);
|
|
27
|
+
function d(e) {
|
|
28
|
+
if (u.has(e)) throw Error(`RPC name "${e}" is reserved by Google Apps Script.`);
|
|
108
29
|
if (!/^[$A-Z_a-z][$\w]*$/u.test(e)) throw Error(`RPC name "${e}" is not a valid JavaScript identifier.`);
|
|
109
30
|
}
|
|
110
|
-
function
|
|
31
|
+
function f(e) {
|
|
111
32
|
let t = [];
|
|
112
33
|
e.hasGet && t.push("function doGet() {}"), e.hasPost && t.push("function doPost() {}");
|
|
113
|
-
for (let n of e.calls)
|
|
34
|
+
for (let n of e.calls) d(n), t.push(`function ${n}() {}`);
|
|
114
35
|
return t.join("\n");
|
|
115
36
|
}
|
|
116
37
|
//#endregion
|
|
117
|
-
//#region src/
|
|
118
|
-
|
|
119
|
-
|
|
38
|
+
//#region src/runtime.ts
|
|
39
|
+
var p = new i("", "", {
|
|
40
|
+
type: "WEB_APP",
|
|
41
|
+
executeAs: "USER"
|
|
42
|
+
}, new s([]), "en", "UTC"), m = {
|
|
43
|
+
CacheService: new r(),
|
|
44
|
+
PropertiesService: new a(),
|
|
45
|
+
Session: new o(p),
|
|
46
|
+
Utilities: new c()
|
|
47
|
+
};
|
|
48
|
+
function h(e = {}) {
|
|
49
|
+
Object.assign(globalThis, {
|
|
50
|
+
...m,
|
|
51
|
+
...e
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/loadAppsScript.ts
|
|
56
|
+
async function g(e, r) {
|
|
57
|
+
h(e.runtime);
|
|
58
|
+
let i = await t({
|
|
59
|
+
configFile: !1,
|
|
60
|
+
root: r.root,
|
|
61
|
+
mode: r.mode,
|
|
62
|
+
envDir: e.envDir,
|
|
63
|
+
appType: "custom",
|
|
64
|
+
ssr: { external: ["@gasboost/app"] },
|
|
65
|
+
server: {
|
|
66
|
+
middlewareMode: !0,
|
|
67
|
+
hmr: !1
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
try {
|
|
71
|
+
let t = i.environments.ssr;
|
|
72
|
+
if (!n(t)) throw Error("Vite SSR environment is not runnable.");
|
|
73
|
+
let r = await t.runner.import(e.entry);
|
|
74
|
+
if (!r.default) throw Error("AppsScript entry must have a default export.");
|
|
75
|
+
return r.default.describe();
|
|
76
|
+
} finally {
|
|
77
|
+
await i.close();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region src/build.ts
|
|
82
|
+
function _(e) {
|
|
83
|
+
let t, n;
|
|
120
84
|
return {
|
|
121
|
-
name: "gasboost",
|
|
85
|
+
name: "gasboost:build",
|
|
86
|
+
apply: "build",
|
|
122
87
|
config() {
|
|
123
|
-
return
|
|
88
|
+
return l(e);
|
|
89
|
+
},
|
|
90
|
+
configResolved(e) {
|
|
91
|
+
t = e;
|
|
124
92
|
},
|
|
125
|
-
buildStart() {
|
|
126
|
-
|
|
93
|
+
async buildStart() {
|
|
94
|
+
n = await g(e, t);
|
|
127
95
|
},
|
|
128
|
-
generateBundle(e,
|
|
129
|
-
let r =
|
|
130
|
-
for (let e of Object.values(
|
|
96
|
+
generateBundle(e, t) {
|
|
97
|
+
let r = f(n);
|
|
98
|
+
for (let e of Object.values(t)) e.type === "chunk" && e.isEntry && (e.code = `${r}\n\n${e.code}`);
|
|
131
99
|
}
|
|
132
100
|
};
|
|
133
101
|
}
|
|
134
102
|
//#endregion
|
|
103
|
+
//#region src/dev.ts
|
|
104
|
+
var v = class extends Error {
|
|
105
|
+
constructor(e) {
|
|
106
|
+
super(e), this.name = "InvalidRpcRequestError";
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
function y(e) {
|
|
110
|
+
let { runtime: t } = e;
|
|
111
|
+
return {
|
|
112
|
+
name: "gasboost:dev",
|
|
113
|
+
apply: "serve",
|
|
114
|
+
configureServer(r) {
|
|
115
|
+
h(t), r.middlewares.use(async (t, i, a) => {
|
|
116
|
+
if (!t.url) {
|
|
117
|
+
a();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
let o = t.url.split("?")[0];
|
|
121
|
+
if (!o.startsWith("/__gasboost/")) {
|
|
122
|
+
a();
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
let s = o.slice(12);
|
|
126
|
+
if (!s || s.includes("/")) {
|
|
127
|
+
a();
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (t.method !== "POST") {
|
|
131
|
+
i.statusCode = 405, i.setHeader("Content-Type", "application/json; charset=utf-8"), i.end(JSON.stringify({ error: {
|
|
132
|
+
name: "MethodNotAllowedError",
|
|
133
|
+
message: "Only POST is allowed."
|
|
134
|
+
} }));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
let { args: a } = await b(t), o = r.environments.ssr;
|
|
139
|
+
if (!n(o)) throw Error("Vite SSR environment is not runnable.");
|
|
140
|
+
let c = await (await o.runner.import(e.entry)).default.dispatch(decodeURIComponent(s), ...a);
|
|
141
|
+
i.statusCode = 200, i.setHeader("Content-Type", "application/json; charset=utf-8"), i.end(c.contents);
|
|
142
|
+
} catch (e) {
|
|
143
|
+
i.statusCode = e instanceof v ? 400 : 500, i.setHeader("Content-Type", "application/json; charset=utf-8"), i.end(JSON.stringify({ error: e instanceof Error ? {
|
|
144
|
+
name: e.name,
|
|
145
|
+
message: e.message,
|
|
146
|
+
stack: e.stack
|
|
147
|
+
} : {
|
|
148
|
+
name: "UnknownError",
|
|
149
|
+
message: String(e)
|
|
150
|
+
} }));
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function b(e) {
|
|
157
|
+
return new Promise((t, n) => {
|
|
158
|
+
let r = [];
|
|
159
|
+
e.on("data", (e) => {
|
|
160
|
+
r.push(typeof e == "string" ? Buffer.from(e) : e);
|
|
161
|
+
}), e.on("error", n), e.on("end", () => {
|
|
162
|
+
let e = Buffer.concat(r).toString("utf-8");
|
|
163
|
+
if (!e) {
|
|
164
|
+
t({ args: [] });
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
let i;
|
|
168
|
+
try {
|
|
169
|
+
i = JSON.parse(e);
|
|
170
|
+
} catch {
|
|
171
|
+
n(new v("Invalid RPC request body. Expected valid JSON."));
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (typeof i != "object" || !i || !("args" in i) || !Array.isArray(i.args)) {
|
|
175
|
+
n(new v("Invalid RPC request body. Expected { args: unknown[] }."));
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
t({ args: i.args });
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
//#endregion
|
|
183
|
+
//#region src/gasboost.ts
|
|
184
|
+
function x(e) {
|
|
185
|
+
return {
|
|
186
|
+
build: _(e),
|
|
187
|
+
dev: y(e)
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
//#endregion
|
|
135
191
|
export { x as gasboost };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { AppsScriptDescription } from "@gasboost/app";
|
|
2
|
+
import { type ResolvedConfig } from "vite";
|
|
3
|
+
import type { GasboostOptions } from "./gasboost";
|
|
4
|
+
export declare function loadAppsScript(options: GasboostOptions, config: ResolvedConfig): Promise<AppsScriptDescription>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gasboost/vite",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "A Vite plugin for building @gasboost/app applications for Google Apps Script.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"google-apps-script",
|
|
@@ -33,10 +33,14 @@
|
|
|
33
33
|
},
|
|
34
34
|
"type": "module",
|
|
35
35
|
"devDependencies": {
|
|
36
|
+
"@types/google-apps-script": "^2.0.12",
|
|
36
37
|
"vite": "^8.2.2"
|
|
37
38
|
},
|
|
38
39
|
"dependencies": {
|
|
39
|
-
"
|
|
40
|
+
"@gasboost/fake-core": "^0.1.2",
|
|
41
|
+
"@gasboost/fake-node": "^0.1.2",
|
|
42
|
+
"typescript": "^7.0.2",
|
|
43
|
+
"@gasboost/app": "1.3.0"
|
|
40
44
|
},
|
|
41
45
|
"publishConfig": {
|
|
42
46
|
"access": "public"
|