@gasboost/vite 1.1.0 → 1.2.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/README.md CHANGED
@@ -603,6 +603,152 @@ URL encoded な RPC 名も decode されます。
603
603
 
604
604
  ---
605
605
 
606
+ ## Client Transport
607
+
608
+ `@gasboost/client` を利用している場合、dev plugin はローカル開発時の transport を自動で Local RPC に切り替えます。
609
+
610
+ アプリケーション側では development / production を判定する必要はありません。
611
+
612
+ ```ts
613
+ import { appsScriptClient } from "@gasboost/client";
614
+ import type { App } from "./server";
615
+
616
+ const { client } = appsScriptClient<App>();
617
+
618
+ const result = await client.sum(1, 2);
619
+ ```
620
+
621
+ Vite Dev Server 上では、`appsScriptClient()` に transport が指定されていない場合、dev plugin が自動的に `FetchTransport` を適用します。
622
+
623
+ ```text
624
+ appsScriptClient()
625
+
626
+ FetchTransport
627
+
628
+ POST /__gasboost/{rpcName}
629
+
630
+ AppsScript.dispatch()
631
+ ```
632
+
633
+ そのため、ローカル開発用に transport を切り替えるコードを書く必要はありません。
634
+
635
+ ```ts
636
+ // 不要
637
+ appsScriptClient({
638
+ transport: import.meta.env.DEV
639
+ ? new FetchTransport({
640
+ endpoint: "/__gasboost",
641
+ })
642
+ : new AppsScriptTransport(),
643
+ });
644
+ ```
645
+
646
+ production build では dev plugin による差し替えは行われません。
647
+
648
+ GAS 上では `appsScriptClient()` のデフォルトである `AppsScriptTransport` がそのまま利用されます。
649
+
650
+ ```text
651
+ appsScriptClient()
652
+
653
+ AppsScriptTransport
654
+
655
+ google.script.run
656
+ ```
657
+
658
+ つまり、同じ application code のまま local development と GAS production の両方で利用できます。
659
+
660
+ ```ts
661
+ const { client } = appsScriptClient<App>();
662
+ ```
663
+
664
+ また、明示的に `transport` を指定した場合はその transport が優先されます。
665
+
666
+ ```ts
667
+ const { client } = appsScriptClient<App>({
668
+ transport: customTransport,
669
+ });
670
+ ```
671
+
672
+ dev plugin が明示指定された transport を上書きすることはありません。
673
+
674
+ ---
675
+
676
+ ## HtmlTemplate variables
677
+
678
+ GAS の `HtmlTemplate` では、`<?= variable ?>` を使用してサーバー側の値を HTML に埋め込めます。
679
+
680
+ ```html
681
+ <script>
682
+ const variables = "<?= variables ?>";
683
+ </script>
684
+ ```
685
+
686
+ GAS 上では `HtmlTemplate` によって評価されますが、Vite Dev Server では GAS のテンプレート処理が実行されません。
687
+
688
+ `@gasboost/vite` では、`template` オプションを指定することで、開発時にこれらの template variables を置換できます。
689
+
690
+ ```ts
691
+ import { gasboost } from "@gasboost/vite";
692
+ import { defineConfig } from "vite";
693
+
694
+ export default defineConfig({
695
+ plugins: [
696
+ gasboost({
697
+ entry: "./src/backend/main.ts",
698
+ template: {
699
+ variables: JSON.stringify({
700
+ scriptId: "local-script-id",
701
+ isSetupCompleted: true,
702
+ isTermsAccepted: true,
703
+ }),
704
+ },
705
+ }).dev,
706
+ ],
707
+ });
708
+ ```
709
+
710
+ 例えば、次の HTML は、
711
+
712
+ ```html
713
+ <script>
714
+ const variables = "<?= variables ?>";
715
+ </script>
716
+ ```
717
+
718
+ Vite の開発環境では次のように変換されます。
719
+
720
+ ```html
721
+ <script>
722
+ const variables =
723
+ '{"scriptId":"local-script-id","isSetupCompleted":true,"isTermsAccepted":true}';
724
+ </script>
725
+ ```
726
+
727
+ 複数の template variable も指定できます。
728
+
729
+ ```ts
730
+ gasboost({
731
+ entry: "./src/backend/main.ts",
732
+ template: {
733
+ environment: "development",
734
+ userName: "Tiger",
735
+ },
736
+ });
737
+ ```
738
+
739
+ ```html
740
+ <p>Environment: <?= environment ?></p>
741
+ <p>User: <?= userName ?></p>
742
+ ```
743
+
744
+ `template` の型は `Record<string, string>` です。
745
+
746
+ 値の serialize は `@gasboost/vite` では行いません。オブジェクトなどを埋め込む場合は、利用側で `JSON.stringify()` などを使用して文字列へ変換してください。
747
+
748
+ `template` による置換は Vite Dev Server でのみ行われます。production build では値を埋め込まず、GAS 上で実際の `HtmlTemplate` が template expression を評価します。
749
+
750
+ ---
751
+
606
752
  # build と dev の責務
607
753
 
608
754
  ```text
@@ -4,6 +4,7 @@ export interface GasboostOptions {
4
4
  entry: string;
5
5
  envDir?: string;
6
6
  runtime?: GasRuntime;
7
+ template?: Record<string, string>;
7
8
  }
8
9
  export declare function gasboost(options: GasboostOptions): {
9
10
  build: Plugin;
package/dist/index.js CHANGED
@@ -105,25 +105,58 @@ var v = class extends Error {
105
105
  constructor(e) {
106
106
  super(e), this.name = "InvalidRpcRequestError";
107
107
  }
108
- };
109
- function y(e) {
110
- let { runtime: t } = e;
108
+ }, y = "@gasboost/client", b = "\0gasboost:client", x = "/__gasboost";
109
+ function S(e) {
110
+ let { runtime: t, template: r } = e, i;
111
111
  return {
112
112
  name: "gasboost:dev",
113
113
  apply: "serve",
114
+ enforce: "pre",
115
+ async resolveId(e, t, n) {
116
+ if (e !== y || this.environment.config.consumer !== "client") return null;
117
+ let r = await this.resolve(e, t, {
118
+ ...n,
119
+ skipSelf: !0
120
+ });
121
+ return r ? (i = r.id, b) : null;
122
+ },
123
+ load(e) {
124
+ if (e !== b) return null;
125
+ if (!i) throw Error("@gasboost/client could not be resolved.");
126
+ let t = JSON.stringify(i);
127
+ return `
128
+ import {
129
+ appsScriptClient as originalAppsScriptClient,
130
+ FetchTransport,
131
+ } from ${t};
132
+
133
+ export * from ${t};
134
+
135
+ export function appsScriptClient(options = {}) {
136
+ return originalAppsScriptClient({
137
+ ...options,
138
+ transport:
139
+ options.transport ??
140
+ new FetchTransport({
141
+ endpoint: ${JSON.stringify(x)},
142
+ }),
143
+ });
144
+ }
145
+ `;
146
+ },
114
147
  configureServer(r) {
115
148
  h(t), r.middlewares.use(async (t, i, a) => {
116
149
  if (!t.url) {
117
150
  a();
118
151
  return;
119
152
  }
120
- let o = t.url.split("?")[0];
121
- if (!o.startsWith("/__gasboost/")) {
153
+ let o = t.url.split("?")[0], s = `${x}/`;
154
+ if (!o.startsWith(s)) {
122
155
  a();
123
156
  return;
124
157
  }
125
- let s = o.slice(12);
126
- if (!s || s.includes("/")) {
158
+ let c = o.slice(s.length);
159
+ if (!c || c.includes("/")) {
127
160
  a();
128
161
  return;
129
162
  }
@@ -135,10 +168,10 @@ function y(e) {
135
168
  return;
136
169
  }
137
170
  try {
138
- let { args: a } = await b(t), o = r.environments.ssr;
171
+ let { args: a } = await w(t), o = r.environments.ssr;
139
172
  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);
173
+ let s = await (await o.runner.import(e.entry)).default.dispatch(decodeURIComponent(c), ...a);
174
+ i.statusCode = 200, i.setHeader("Content-Type", "application/json; charset=utf-8"), i.end(s.contents);
142
175
  } catch (e) {
143
176
  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
177
  name: e.name,
@@ -150,10 +183,22 @@ function y(e) {
150
183
  } }));
151
184
  }
152
185
  });
186
+ },
187
+ transformIndexHtml(e) {
188
+ if (!r) return e;
189
+ let t = e;
190
+ for (let [e, n] of Object.entries(r)) {
191
+ let r = RegExp(`<\\?=\\s*${C(e)}\\s*\\?>`, "g");
192
+ t = t.replace(r, () => n);
193
+ }
194
+ return t;
153
195
  }
154
196
  };
155
197
  }
156
- function b(e) {
198
+ function C(e) {
199
+ return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
200
+ }
201
+ function w(e) {
157
202
  return new Promise((t, n) => {
158
203
  let r = [];
159
204
  e.on("data", (e) => {
@@ -181,11 +226,11 @@ function b(e) {
181
226
  }
182
227
  //#endregion
183
228
  //#region src/gasboost.ts
184
- function x(e) {
229
+ function T(e) {
185
230
  return {
186
231
  build: _(e),
187
- dev: y(e)
232
+ dev: S(e)
188
233
  };
189
234
  }
190
235
  //#endregion
191
- export { x as gasboost };
236
+ export { T as gasboost };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gasboost/vite",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "A Vite plugin for building @gasboost/app applications for Google Apps Script.",
5
5
  "keywords": [
6
6
  "google-apps-script",