Google Apps Script で
Angular(+2) の
手順、
前提
以下の
OS
sw_vers ProductName: Mac OS X ProductVersion: 10.14.3 BuildVersion: 18D109
Node.js の
バージョン node -v v11.8.0
Angular の
バージョン ng version _ _ ____ _ ___ / \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _| / △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | | / ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | | /_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___| |___/ Angular CLI: 7.3.1 Node: 11.8.0 OS: darwin x64 Angular: ... Package Version ------------------------------------------------------ @angular-devkit/architect 0.13.1 @angular-devkit/core 7.3.1 @angular-devkit/schematics 7.3.1 @schematics/angular 7.3.1 @schematics/update 0.13.1 rxjs 6.3.3 typescript 3.2.4
プロジェクトの ディレクトリ構成に ついて
Angular プロジェクトのfrontend
、backend
を
ここは
Treeコマンドの
結果 tree -L 2 . ├── backend │ ├── LICENSE.txt │ ├── dist │ ├── node_modules │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── tsconfig.json │ ├── tslint.json │ └── webpack.config.js ├── build.sh └── frontend ├── README.md ├── angular.json ├── dist ├── e2e ├── extra-webpack.config.js ├── node_modules ├── package-lock.json ├── package.json ├── src ├── tsconfig.json └── tslint.json
build.sh の
内容
プロジェクトルートのbuild.sh
の中身です。
frontend
のビルド後に、 backend
のclasp プロジェクトを デプロイしています。
もっとここは いい 方法が ありそうですが、 これでも 実現が できました。 #!/bin/sh cd ./frontend ng build --prod cd ../backend npm run deploy
Angular CLI を インストール、 Angular プロジェクトフォルダの 作成
フロンドエンドの
Angular CLI
のインストール
Angular CLI
をインストールします。 npm install -g @angular/cli
プロジェクトフォルダの
作成
プロジェクトルートに移動して、 ng
コマンドでAngular プロジェクトを 作成します。 ng new frontend
Angular プロジェクトを Google Apps Script に デプロイする ために 調整する
Angular の
Angular 6 でng eject
コマンドはng eject
コマンドを
ng eject
実行時のメッセージ メッセージにng eject The 'eject' command has been disabled and will be removed completely in 8.0. The new configuration format provides increased flexibility to modify the configuration of your workspace without ejecting. There are several projects that can be used in conjuction with the new configuration format that provide the benefits of ejecting without the maintenance overhead. One such project is ngx-build-plus found here: https://github.com/manfredsteyer/ngx-build-plus
記載されている ngx-build-plus
のインストールだけではうまく 動かず、 Angular7で webpack configを 調整して バンドルサイズや 挙動を 自在に 操る(ag-Grid入門付き!) - Qiita を 参考に 設定した ところうまく いきました。
調整した内容に ついて 以下に 記載します。 Angular プロジェクトルートに
移動
ここからの作業は、 Angular プロジェクトルート で 行います。 cd frontend
webpack の
調整に 必要な パッケージの インストール
以下、パッケージの インストールを 行います。 npm i -D @angular-builders/custom-webpack npm i -D ngx-build-plus npm i -D webpack
angular.json
の編集
angular.json
内の記述を 以下のように 編集します。 //builder を変更する //"builder": "@angular-devkit/build-angular:browser" "builder": "@angular-builders/custom-webpack:browser", "options": { "outputPath": "dist/frontend", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.app.json", //webpack の追加設定ファイルを指定する "customWebpackConfig": { "path": "./extra-webpack.config.js" },
extra-webpack.config.js
で使用する パッケージの インストール
extra-webpack.config.js
で使用する パッケージを インストールします。
html-webpack-inline-source-plugin は出力ファイルを HTMLファイル 1つにまとめる ため、
webpack-cdn-plugin はAngular 関連の JavaScript を CDN から 取得する ために 使います。 npm i -D html-webpack-plugin npm i -D html-webpack-inline-source-plugin npm i -D webpack-cdn-plugin
extra-webpack.config.js
の作成
extra-webpack.config.js
の記述は 以下に なります。 const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin'); const WebpackCdnPlugin = require('webpack-cdn-plugin'); module.exports = { // cdn から取得する対象のライブラリを、externals に指定する "externals": { "rxjs": "rxjs", "zone.js": "Zone", "@angular/core": "ng.core", "@angular/common": "ng.common", "@angular/platform-browser": "ng.platformBrowser", "@angular/router": "ng.router" }, plugins: [ new HtmlWebpackPlugin({ filename: 'index.html', template: './src/index.html', // webpack-cdn-plugin で cdn から読み込む対象にしているjs,cssはインライン化の対象外にする inlineSource: '^(?!http).*.(js|css)$', // Google Apps Script で読み込む際に都合が悪いので、minify時の動作を変更する minify: { removeAttributeQuotes: false, removeScriptTypeAttributes: false } }), new HtmlWebpackInlineSourcePlugin(), // Angular 関連のライブラリはCDNから取得する new WebpackCdnPlugin({ modules: [ { name: 'rxjs', var: 'rxjs', path: 'bundles/rxjs.umd.min.js' }, { name: '@angular/core', var: 'ng.core', path: 'bundles/core.umd.min.js' }, { name: '@angular/common', var: 'ng.common', path: 'bundles/common.umd.min.js' }, { name: '@angular/platform-browser', var: 'ng.platformBrowser', path: 'bundles/platform-browser.umd.min.js' }, { name: '@angular/router', var: 'ng.router', path: 'bundles/router.umd.min.js' }, { name: 'zone.js', var: 'Zone', path: 'dist/zone.js' } ], publicPath: '/node_modules' }) ] }
app-routing.module.ts の
調整
Webアプリケーションとして 公開時、 HTML は 以下のような URL に 割り当てられます。
https://xxxxxxxxxxxxxxxxxxxxxxxxxx-script.googleusercontent.com/userCodeAppPanel
このURL に 対して Angular の Router の マッピングが ないと 以下のような エラーが 発生します。 このcore.umd.min.js:563 ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'userCodeAppPanel' Error: Cannot match any routes. URL Segment: 'userCodeAppPanel'
ため 自動生成された app-routing.module.ts
のRoutes の 定義を 以下のように 変更しました。 import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { AppComponent } from './app.component'; const routes: Routes = [ { path: '', component: AppComponent, pathMatch: 'full' }, // root 以外の path を 空コンポーネントにマッピングしておく { path: '**', children: [] } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
Angular プロジェクト に
claspプロジェクトの 作成
clasp プロジェクトは、
追加で
パッケージの
インストール
Angular プロジェクトでbuild した html を clasp の デプロイ時に 含めたいので、 copy-webpack-plugin
をインストールしました。 npm i -D copy-webpack-plugin
backend/webpack.config.js
の修正
copy-webpack-plugin
で対象の ファイルを コピーする 記述を 追加しました。 設定はconst path = require('path'); const GasPlugin = require("gas-webpack-plugin"); const CopyWebpackPlugin = require('copy-webpack-plugin') module.exports = { mode: 'development', entry: './src/index.ts', devtool: false, output: { filename: 'bundle.js', path: path.join(__dirname, 'dist') }, module: { rules: [ { test: /\.ts$/, use: 'ts-loader' } ] }, resolve: { extensions: [ '.ts', '.js' ] }, plugins: [ new GasPlugin(), // Angular プロジェクトでビルドした、index.html を、dist ディレクトリ配下にコピーする new CopyWebpackPlugin([ { from: "../frontend/dist/frontend/index.html", to: "./index.html", toType: 'file' } ]) ] };
以上です。
これで、プロジェクトルートで、 build.sh
を実行し、 Google Apps Script で Web アプリケーションと して 公開すると、 ページが 表示されるようになります。
その他試した こと、 うまくいかないこと
上記作業中に
dynamic-cdn-webpack-plugin
の利用
webpack-cdn-plugin でのパスの 指定が 面倒なので、 dynamic-cdn-webpack-plugin - npm を 使おうとしましたが、 以下、 module-to-cdn で rxjs 6 以降の cdn の パスの 解決が できない 問題が あり、 webpack-cdn-plugin を 使用しました。
support rxjs 6 and only support version 5 and above by juanferreira · Pull Request #13 · mastilver/module-to-cdncopy-webpack-plugin
を使わずに、 html-webpack-plugin
を使っていた。
copy-webpack-plugin
の存在を 知らず、 html-webpack-plugin
を使って Angular プロジェクトの ファイルコピーを 行なっていました。
この方法でも、 html-webpack-exclude-assets-plugin
と併用する ことで、 ファイルコピーが 実現可能ですが、 あまりいいやり方ではないです。
以下、パッケージを インストールして、 以下、npm i -D html-loader npm i -D html-webpack-exclude-assets-plugin npm i -D html-webpack-plugin
webpack.config.js で ファイルコピーは 実現できました。 const path = require('path'); const GasPlugin = require("gas-webpack-plugin"); const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlWebpackExcludeAssetsPlugin = require('html-webpack-exclude-assets-plugin'); module.exports = { mode: 'development', entry: './src/index.ts', devtool: false, output: { filename: 'bundle.js', path: path.join(__dirname, 'dist') }, module: { rules: [ { test: /\.ts$/, use: 'ts-loader' }, { test: /\.html$/, loader: "html-loader" } ] }, resolve: { extensions: [ '.ts', '.js' ] }, plugins: [ new GasPlugin(), // Angularプロジェクトの new HtmlWebpackPlugin({ excludeAssets: [/\.js$/] , filename: "./index.html", template: "../frontend/dist/frontend/index.html", }), new HtmlWebpackExcludeAssetsPlugin() ] };
favicon.icoの
base64エンコード
index.html 内に、favicon.ico の 記載が ありますが、 webpack で favicon.ico を base64 エンコードする 方法が わからず、 一旦放置しました。
Google Apps Script から直接 URL を 指定するか、 gulp ですが favicon を base64 エンコードする plugin が あったので、 後日実施しようかと 思います。 - GASで
作成した Webページに ファビコンを 設定する 方法 - gulp-base64-favicon - npm
参考
以下、
- Angular7で
webpack configを 調整して バンドルサイズや 挙動を 自在に 操る(ag-Grid入門付き!) - Qiita clomie/gas-vue-typescript: Google Apps Script with Vue.js, TypeScript, …
Angular7で
webpack configを 調整して バンドルサイズや 挙動を 自在に 操る(ag-Grid入門付き!) - Qiita Angular
<router-outlet >
displays template twice - Stack OverflowGoogle Apps Script で
AngularJSを 使った Single Page Application を 構築・公開する 方法(基礎編) - Qiita
以上です。
コメント