はじめに
この記事は以前投稿したVue.js製のSPAをGoogleAppsScriptにデプロイするためのWebpack設定に対する、Vue CLI v3向けのアップデートです。
Vue.js側のビルド設定方針
GASのWebAppsで公開されるWebページは、doGet
関数で返すHTMLがエスケープされて配信され、クライアント側でevalするような仕組みになっていて、このHTMLにJS、CSS含めすべてのリソースをインライン化して配信する必要があります。
ただし、HTMLのサイズが大きくなってくると画面の表示にかなり多くの時間がかかるようになってきます。このため、npmモジュールやwebフォントなど外部から取得できるものはなるべくそちらを使う方針が良いと思います。
設定は主にvue.config.jsのchainWebpack
プロパティで行います。
chainWebpack
については、適宜公式ドキュメントのサンプルやwebpack-chainのREADMEを参照してください。正直とっつきにくいです。もう少しシンプルに書ける方法等あれば教えてください。
vue.config.jsサンプル
module.exports = {
chainWebpack: config => {
// disable prefetch and preload
config.plugins.delete('prefetch')
config.plugins.delete('preload')
// Make js and css files inline into index.html
config
.plugin('html-inline-source')
.use(require('html-webpack-inline-source-plugin'))
config.plugin('html').tap(args => {
args[0].inlineSource = '(/css/.+\\.css|/js/.+\\.js)'
return args
})
// make inline images
config.module
.rule('images')
.use('url-loader')
.options({})
// make inline media
config.module
.rule('media')
.use('url-loader')
.options({})
// make inline fonts
config.module
.rule('fonts')
.use('url-loader')
.options({})
// make inline svg
config.module
.rule('svg')
.uses.delete('file-loader')
.end()
.use('url-loader')
.loader('url-loader')
.options({})
// Get npm modules from CDN
config.plugin('webpack-cdn').use(require('webpack-cdn-plugin'), [
{
modules: [
{
name: 'vue',
var: 'Vue',
path: 'dist/vue.runtime.min.js'
},
{
name: 'vue-router',
var: 'VueRouter',
path: 'dist/vue-router.min.js'
}
]
}
])
if (process.env.NODE_ENV === 'production') {
// html minify settings for GAS
config.plugin('html').tap(args => {
args[0].minify.removeAttributeQuotes = false
args[0].minify.removeScriptTypeAttributes = false
return args
})
}
}
}
下記のnpmモジュールのインストールが必要です。
$ npm i -D html-webpack-inline-source-plugin webpack-cdn-plugin
少し解説します。
prefetch, preloadの無効化
デフォルトで有効になっていますが、GASではインライン化する都合上無効化します。
module.exports = {
chainWebpack: config => {
config.plugins.delete('prefetch')
config.plugins.delete('preload')
}
}
JS,CSSのインライン化
html-webpack-inline-source-pluginを導入しましょう。
html-webpack-pluginにinlineSource
プロパティを設定するのを忘れてハマりがちなので注意。後述するCDN化されたファイルに反応しないよう、パスで指定されたファイルのみ対象にします。
module.exports = {
chainWebpack: config => {
config
.plugin('html-inline-source')
.use(require('html-webpack-inline-source-plugin'))
config.plugin('html').tap(args => {
args[0].inlineSource = '^(/css/.+\\.css|/js/.+\\.js)'
return args
})
}
}
静的リソースのインライン化
画像などのファイルもすべてData URI Scheme化する必要があります。
しかし、デフォルトのurl-loaderの設定ではlimitが設定されており、4KB以上のファイルは抽出されてファイルパスへの参照に置き換えられてしまいます。
それ以上のサイズのファイルを含めたい場合、下記のようにurl-loaderのoptionをデフォルトに戻し、limitを無効化するなどの対応が必要になります。
module.exports = {
chainWebpack: config => {
config.module
.rule('images')
.use('url-loader')
.options({})
}
}
npmモジュールのCDN参照化
webpack-cdn-pluginを導入すると、参照しているnpmモジュールを、CDNを参照するように変換してくれます。
Vuetifyなどcssも一緒にnpmモジュールにバンドルされている場合はcssの方もCDNを参照するように設定した上で、importされないようexternalsを設定する必要があります。
module.exports = {
chainWebpack: config => {
config.plugin('webpack-cdn').use(require('webpack-cdn-plugin'), [
{
modules: [
{
name: 'vue',
var: 'Vue',
path: 'dist/vue.runtime.min.js'
},
{
name: 'vue-router',
var: 'VueRouter',
path: 'dist/vue-router.min.js'
}
]
}
])
}
}
minifyの設定
デフォルトのHtmlWebpackPluginの設定では、productionモードではminifyされすぎてHtmlServiceで読み込む際にエラーになってしまうようです。
いろいろと試したところ、removeAttributeQuotes
, removeScriptTypeAttributes
の2つをfalse
にすることでGASでも読み込めるようになりました。
module.exports = {
chainWebpack: config => {
if (process.env.NODE_ENV === 'production') {
// html minify settings for GAS
config.plugin('html').tap(args => {
args[0].minify.removeAttributeQuotes = false
args[0].minify.removeScriptTypeAttributes = false
return args
})
}
}
}
おわりに
下記のリポジトリにて、Vue.js+TypeScriptでGASのWebAppsにデプロイ可能な構成を試しています。
上記設定でビルドされるindex.htmlを確認したい場合などに使ってください。