勉強日記

チラ裏

Programming TypeScript ch12 Building and Running TypeScript / npmパッケージ公開した

www.oreilly.com


Building Your TypeScript Project

Project Layout

  • トップレベルのsrc/dist/を作るの推奨

Artifacts

Type 拡張子 tsconfig.json flag Emitted by default?
JavaScript .js emitDeclarationOnly === false yes
Source maps .js.map sourceMap === true no
Type declarations .d.ts declaration === true no
Declaration maps .d.ts.map declarationMap === true no

Dialing In Your Compile Target

  • transpileとpolyfill
    • transpile: 古い機能に自動変換
        • for..of -> for
        • async/await -> Promise/then
    • Polyfill: ない機能の実装を補う
      • MapとかSetとか
      • Array.prototype.findとか
  • TSCはtranspileするがpolyfillはしてくれない
  • tsconfig
    • target
      • transpileのターゲット
    • lib
      • polyfillを導入したときに、「使えるよ」と教えてあげるやつ
        • polyfillではないがdomなどもこれ

Enabling Source Maps

  • 一般に、プロダクションでもsource mapはデプロイしたほうが良い
  • ただし、難読化によるセキュリティに信を置いているならばこの限りではない

Project References

  • コンパイル時間はコードベースの量にだいたい比例して長引いていく
  • これを劇的に開眼するのがproject references

column: Using extends to Reduce tsconfig.json Boilerplate

  • 全サブプロジェクトで設定を共有したいときに便利

Error Monitoring

  • 実行時にエラーが出ないわけではないので監視を入れる必要はある
    • Sentry
    • Bugsnag

Running Typescript on the Server

  • targetをES2015 (古いNodeJSならばES5)に設定する
    • import/exportrequire/module.exportsにトランスパイルされる
  • source map使え
  • 監視、ロギング、レポートツールの多くはビルトインのsource mapサポートがある

Running Typescript in the Browser

  • モジュールバンドラによって選ぶべきtargetが変わってくる
  • TSC自体もoutFileフラグを指定することでバンドルを行えるが…
    • SystemJSとAMDにしか対応していない
    • バンドル専用のツールに比べると機能面で弱い
  • TSに限らない一般論
    • dynamic import使え
    • バンドラのコード自動分割の恩恵に与れ
      • 無用なロードを減らす
    • パフォーマンスを(できれば実データで)計測せよ
      • New Relic
      • Datadog
    • polifill
      • 全環境共通
      • 実行環境に応じてdynamic importする

Publishing Your TypeScript Code to NPM

【補】実際に npm publish してみた

www.npmjs.com

git ignore npm ignore
ts no yes
d.ts yes no
js yes no
  • ビルド成果物のみ含める
  • .npmignoreがあればそれを、無ければ.gitignoreが使用される
    • 【補】.npmignoreは同階層の.gitignoreしか打ち消さない

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "lib": ["es2015"],
    "declaration": true,
    "sourceMap": true,
    "strict": true,
    "noImplicitAny": true,
    "esModuleInterop": true,
    "outDir": "./dist"
  },
  "include": [
    "src/**/*"
  ]
}
  • "declaration": true
    • 型定義ファイルを出力する
  • "sourceMap": true
    • デバッグのためにsource mapファイルを含める

package.json

{
  "name": "@d.horiyama/yaml_schema",
  "version": "0.0.7",
  "description": "Specify YAML by JSON Schema v7 in YAML.",
  "repository": {
    "type" : "git",
    "url" : "https://github.com/wand2016/yaml-schema"
  },
  "main": "dist/index.js",
  "types": "dist/index.d.js",
  "bin": "bin/yaml_schema",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "prepublishOnly": "tsc -d"
  },
  "keywords": [
    "yaml",
    "JSON Schema"
  ],
  "author": "Daiki Horiyama",
  "license": "MIT",
  "dependencies": {
    "ajv": "^6.12.2",
    "ajv-errors": "^1.0.1",
    "commander": "^5.1.0",
    "get-stdin": "^8.0.0",
    "js-yaml": "^3.13.1",
    "typescript": "^3.9.2"
  },
  "devDependencies": {
    "@types/ajv-errors": "^1.0.2",
    "@types/js-yaml": "^3.12.4",
    "@types/node": "^14.0.4"
  }
}
  • "name": "@d.horiyama/yaml_schema"
    • Scoped Package
    • @d.horiyama名前空間の下に配置
      • 貴重なグローバル名前空間をクソパッケージでむやみに汚さない
  • "version": "0.0.7"
    • versionを上げないとpublishできない
  • "bin": "bin/yaml_schema"
    • npxnpm runで実行するためのexecutableを配置する
      • npm install時にnode_modules/.bin/にsymlinkが配置される
  • "prepublishOnly": "tsc -d"
    • publish前に実行するコマンド
    • d.tsファイル込でビルド

bin/yaml_schema

#!/usr/bin/env node
require('../dist/index.js')
  • 公開する
npm publish --access=public
  • scoped packageのpublish時は--access=publicが必要
    • オプションを付けないとデフォルトでprivate packageとみなされ、課金が必要となる (402 Payment Required)

Triple-Slash Directives

  • めったに使われない

The Types Directive

/// <reference types="./global" />
/// <reference types="jasmine" />

コンパイル結果にrequireやimportを含めたくない場合に

The amd-module Directive

  • AMDモジュール出力
{
  "compilerOptions": {
    "module": "amd",
...

Hoge.ts

export class Hoge {}

Hoge.js

define(["require", "exports"], function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    class Hoge {
    }
    exports.Hoge = Hoge;
});
//# sourceMappingURL=Hoge.js.map
  • triple-slashでモジュール名をつけることができる

Hoge.ts

/// <amd-module name='Hoge' />
export class Hoge {}

Hoge.js

define("Hoge", ["require", "exports"], function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    /// <amd-module name='Hoge' />
    class Hoge {
    }
    exports.Hoge = Hoge;
});
//# sourceMappingURL=Hoge.js.map

英語

  • swath
  • curb
    • 縁石
      • FTTCのCがこれ
    • 制限
  • inflict pain
    • 痛みを与える