LoginSignup
1
1

More than 1 year has passed since last update.

viteでブラウザ上でtypeormを使ってみたメモ

Posted at

概要

前回、ブラウザのメモリ上でsqliteを動かすsql.jsを試した。
型をつけてO/Rマッパーを導入してみる。
一応動くことは確認できたが、無理やり感は否めない。
ソースコード

typescript設定

tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
+    "experimentalDecorators": true, // アノテーションが使えるようにする
    // "emitDecoratorMetadata": true, // esbuildでは emitDecoratorMetadata は未対応
    "sourceMap": true
  },
}

typeormはアノテーションを利用するため、typescriptがそれを許可するようにする。
emitDecoratorMetadataはtypeormではtrueにするよう指示しているが、
viteが利用しているesbuild非対応なので設定しない。
swcをesbuildの代わりに利用する方法もあるようだが、設定ファイルをesbuild用に作っていたため断念。
一度試したが、buildが通らなくなったので使用を諦めた*

モデル作成

domain/todo/models/User.ts
/* eslint-disable unused-imports/no-unused-vars */
import {
  Entity,
  Column,
  CreateDateColumn,
  UpdateDateColumn,
  BaseEntity,
  PrimaryColumn,
} from 'typeorm/browser'

@Entity()
export class User extends BaseEntity {
  @PrimaryColumn({ type: 'text' })
  public id!: string

  @Column({ type: 'text' })
  public name!: string

  @CreateDateColumn()
  public readonly createdAt!: Date

  @UpdateDateColumn()
  public readonly updatedAt!: Date
}

emitDecoratorMetadatafalseのため、reflect-metadataが使えない。
公式ドキュメントの通り、@Column() public name!: stringと設定すると、以下のエラーが発生する。
esbuildを通すと、型情報が消えるので、reflect-metadataで値を取得することができない。

Column.ts:192 Uncaught ColumnTypeUndefinedError: Column type for User#name is not defined and cannot be guessed. Make sure you have turned on an "emitDecoratorMetadata": true option in tsconfig.json. Also make sure you have imported "reflect-metadata" on top of the main entry file in your application (before any entity imported).If you are using JavaScript instead of TypeScript you must explicitly provide a column type.
    at Column.ts:192:23
    at __decorateClass (User.ts:7:24)
    at User.ts:18:10

DB準備

domain/sqlite/initSQL.ts
import initSqlJs, { SqlJsStatic } from 'sql.js'

export const initSQL = async (wasmFileDirPath: string) => {
  const SQL: SqlJsStatic = await initSqlJs({
    locateFile: (file) => `${wasmFileDirPath}/${file}`,
  })
  // typeorm用にwindow.SQLに保存
  Object.assign(globalThis as any, { SQL })

  return SQL
}
domain/todo/index.ts
import { DataSource } from 'typeorm/browser'
import { WASM_FILE_PATH } from '../sqlite/constants'
import { initSQL } from '../sqlite/initSQL'
import { User } from './models/User'
import type { PromiseReturnType } from '@/types'

const initRepository = async () => {
  await initSQL(WASM_FILE_PATH)

  const conn = new DataSource({
    type: 'sqljs', // this connection search window.SQL on browser
    entities: [User],
    synchronize: true,
    logging: ['query', 'schema'],
  })
  await conn.initialize()

  const userRepository = conn.getRepository(User)
  return { userRepository }
}
let repositories: PromiseReturnType<typeof initRepository> | undefined
export const getRepositories = async () => {
  if (repositories) return repositories
  repositories = await initRepository()
  return repositories
}

結論

typeormがもともとNode.js上で動かすものなので、いろいろハマった。
また、ファイルサイズが大きいため、クライアントには不向きかもしれない。

image.png

参考

typeorm + absurd-sql on Browser のロマン構成

github - typeorm - sqljs-data-source-options
typeorm/typescript-example

Node.js × TypeScriptのORM、TypeORMをMySQLで試す

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1