GAS HtmlServices + Vue3 + Vite + Clasp でのデプロイ後エラー対策
こんにちは、luthです
ノンプログラマーですが、社内ツール開発でワンオフ物としてWebAppをGASで公開していたりします
今回は、Vue@3.4.0にバージョンアップした際に数時間引っかかったエラーの対応についてです
経緯はこちら
後述のnpmパッケージはこちら
環境情報
- GoogleAppsScript [HtmlServices]
- Node.js
- @google/clasp
- vue@^3.4.0
※@3.3.x以下では発生なし - vite
- vite-plugin-singlefile
*上記構成については下記記事を参照させていただきました、ありがとうございました…!
課題点
運用中のVueアプリのメンテナンスで、Vue@3.4.0へのバージョンアップを検証していました
ローカル開発ではブラウザで問題なく動いたため、claspでGASにアップロードし、デプロイテストをしたところ、何もマウントされない状態になってしまいました
コンソールを見ると、下記エラーで止まってマウントまで至らなかったようです
Uncaught SyntaxError: Invalid destructing assignment target
このエラー自体はデフォルト引数に関するエラーです
ただ、ローカルでのデフォルト引数の設定自体は問題ありませんでしたし、
何よりビルド後のローカルのhtmlファイルをブラウザで開いても、このエラーは出ずに正常処理されます
宇宙猫🐈になりかけながらも、デプロイ後のソースを追ったところ、ローカルとの差分は以下の通りでした
i = `https://vuejs.com/errors/#runtime-${n}`
i = `https:// /* 謎の改行 */
${T}`, message: "alert", // 本来はかなり先のコード
GASはWebアプリをブラウザで描画する際、生のHTML+JSを利用するわけではなく、2重のiframeを使って埋め込むことで、アプリ利用者向けのセキュリティ担保を目指しています
おそらくは、そのデプロイ後のソースを読み込んでiframe内で展開する時に、ソースがめちゃ削られてる感じです
Vue@3.3.xの時のビルドソースでは以下のようになっていましたので、GASがソース内のURLを、セキュリティ上の理由だかで削る正規表現がめちゃ広めなものなんでしょう…
i = n;
対策plugin
URLが置換されるのが問題なら事前にURLを潰そう、ということで、
Viteプラグイン用に下記のように記述してみました
import type { Plugin } from 'vite';
export interface ReplaceRule {
from: string | RegExp;
to: string;
}
export const PRESET_REPLACE_MASTER: Array<ReplaceRule> = [
{
from: /\=`https:\/\/vuejs\.org\/errors\/#runtime-\$\{(.+?)\}`/g,
to: '=$1',
},
{
from: /\=`https:\/\/vuejs\.org\/errors{0,1}-reference\/#runtime-\$\{(.+?)\}`/g,
to: '=$1',
},
// for scriptlet of apps script
{
from: /"(\<\?\!{0,1}\={0,1}.+?\?\>)"/g,
to: "'$1'",
},
];
export const vueOnGas = (
replaceMaster: Array<ReplaceRule> = PRESET_REPLACE_MASTER,
): Plugin => ({
name: 'vue-on-gas',
generateBundle(_outputOptions, outputBundle) {
const chunkNames = Object.keys(outputBundle);
chunkNames.forEach((chunkName) => {
const chunk = outputBundle[chunkName];
replaceMaster.forEach(({ from, to }) => {
const isMatch =
typeof from === 'string'
? chunk.code.indexOf(from) !== -1
: from.test(chunk.code);
if (isMatch) {
console.info(
`[Vue on GoogleAppsScript plugin] match with pattern: ${from.toString()}`,
);
chunk.code = chunk.code.replace(from, to);
}
});
outputBundle[chunkName] = chunk;
});
},
});
viteの設定に組み込むのはこんな感じ
置換設定を変えたい場合は引数にマスタを入れてあげれば置換処理に使えます
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { viteSingleFile } from 'vite-plugin-singlefile';
import { vueOnGas } from './plugins/vite-plugin-vueOnGoogleAppsScript';
export default defineConfig({
plugins: [
vue(),
viteSingleFile(),
vueOnGas(),
],
build: {
outDir: 'dist',
},
});
というnpmパッケージ
そんな内容のnpmパッケージを公開しましたので、
よろしければご利用くださいませ。
単純な置換処理ですが、プラグインにできたことでビルド設定さえすれば以後は気にせずに開発~デプロイを実行できるようになりました
GAS+Vue+Vite
の組み合わせはニッチな気がしますが、同構成をご利用の方、よろしければご利用ください…!
Discussion