株式会社TRIVE GROUP
くまぽん(なかの)
中野 伸吾
余談
検証の一環で、React/Next.jsのアプリケーションに Ionic@coreの導入を試した
→ ルーティング設定周りで沼にハマりそうになったので、早めに検証を打ち止めた
最初の有力候補は
React/Ionicでした
SPA × Dynamic Rendering
SSR
※Nuxt/React or Ionic/Angular (+ Angular Universal)
選択肢は、以下の2択
Ionic系のCustom Elementsの変換が上手くいかない
Rendertronを使って検証
Ionicは利用したい+SPAは
(SEOリスクを回避するのが)厳しい
↓
Ionic Angular (+Angular Universal)
の採用を決めた
const routes: Routes = [
{
path: '',
loadChildren: () => {
if (typeof window !== 'undefined' && isPlatform('capacitor')) {
// アプリ(下タブあり)
return import('./tabs/tabs.module').then((m) => m.TabsPageModule);
} else {
// Web(下タブなし)
return import('./about/about.module').then((m) => m.AboutPageModule);
}
},
},
↓
結果的にFirebase Authを採用した
import { Component, Inject, OnInit } from '@angular/core';
import { Meta } from '@angular/platform-browser';
@Component({
selector: 'app-detail',
templateUrl: './detail.page.html',
styleUrls: ['./detail.page.scss'],
})
export class DetailPage implements OnInit {
constructor(
public meta: Meta,
@Inject(Localstorage) private localStorage
) {}
ngOnInit() {
// これはOK
this.meta.updateTag({
property: 'og:url',
content: `${environment.frontUrl}${this.router.url}`,
});
}
ionViewWillEnter() {
// こちらはNG
this.meta.updateTag({
property: 'og:url',
content: `${environment.frontUrl}${this.router.url}`,
});
}
}
本番ビルドするとIonicがMaterial Designモード固定になる
(iOSのUserAgentであっても、無条件でmdモードになる)
公式Issueでも取り上げられている
既知の伸び代
import { Component, Inject, PLATFORM_ID } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { isPlatformBrowser } from '@angular/common';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.scss'],
})
export class AppComponent {
static isBrowser = new BehaviorSubject<boolean>(null);
constructor(@Inject(PLATFORM_ID) private platformId: any) {
AppComponent.isBrowser.next(isPlatformBrowser(platformId));
}
}
src/app/app.component.ts
import { Injectable } from '@angular/core';
import { AppComponent } from '../app/app.component';
class LocalStorage implements Storage {
[name: string]: any;
readonly length: number;
clear(): void {}
getItem(key: string): string | null {
return undefined;
}
key(index: number): string | null {
return undefined;
}
removeItem(key: string): void {}
setItem(key: string, value: string): void {}
}
@Injectable({
providedIn: 'root',
})
export class Localstorage implements Storage {
private storage: Storage;
constructor() {
this.storage = new LocalStorage();
AppComponent.isBrowser.subscribe((isBrowser) => {
if (isBrowser) {
this.storage = localStorage;
}
});
}
[name: string]: any;
length: number;
clear(): void {
this.storage.clear();
}
getItem(key: string): string | null {
return this.storage.getItem(key);
}
key(index: number): string | null {
return this.storage.key(index);
}
removeItem(key: string): void {
return this.storage.removeItem(key);
}
setItem(key: string, value: string): void {
return this.storage.setItem(key, value);
}
}
src/local-storage.ts
import { Injectable, Inject } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/auth';
import { FirebaseUser } from '../../model/user';
import { Localstorage } from '../local-storage';
import * as firebase from 'firebase/app';
import 'firebase/auth';
@Injectable({
providedIn: 'root',
})
export class AuthenticationService {
constructor(
public ngFireAuth: AngularFireAuth,
@Inject(Localstorage) private localStorage
) {}
getCurrentUser() {
this.ngFireAuth.authState.subscribe((firebaseUser: FirebaseUser) => {
this.localStorage.setItem('user', JSON.stringify(firebaseUser));
});
}
}
src/app/service/authentication.service.ts ※ 一部抜粋
async getItem(itemId: number): Promise<Observable<Item>> {
let params;
await this.authService.initFirebaseAuth();
if (firebase.auth().currentUser) {
const token = await firebase.auth().currentUser.getIdToken(true);
params = new HttpParams().set('token', token);
}
return this.http
.get<Item>(`${this.baseUrl}/items/${itemId}`, { params })
.pipe(
map((item) => {
return item;
})
);
}
例
【こんな方にぴったり】
◆ 創業メンバーとガッツリ働いてみたい方
◆ 事業視点と技術向上を両立したい方
◆ これから伸びていく市場で働いてみたい方
◆ 会社や事業の成長を肌で感じたい方
◆ この世にまだないプロダクトを生み出したい方
【具体的な仕事内容】
◆ 自社サービス/新規事業のグロースに向けた開発業務(フロントエンド・バックエンド)
【開発環境】
・Ruby (Ruby on Rails)
・Ionic/Angular
・MySQL
・Docker
・Firebase(Auth/Analytics等)
・GCP (App Engine/Cloud SQL/Cloud Function等)
・GitHub Actions (自動テスト/自動デプロイ等)
気になる方は、私のTwitter宛に
DMお待ちしてます!!