たにしきんぐダム

プログラミングやったりゲームしてます

sbt-npm-package でシュッと scala.js のビルド成果物を npm にアップロードする

Scala Advent Calendar 2022 - Qiita 1日目の記事です

scala.js でビルドした成果物を npm にアップロードすることありますか? 私はある。

普通に scala.js でビルドした js を npm にアップロードしようとするとこういう感じの流れになります。

  • sbt fullOptJS とかで js にビルド
  • ビルド成果物(.../target/scala-2.13/foo-opt.js とか) を適当なディレクトリにコピー
  • そのディレクトリに package.json と、npmにアップロードする README.md を設置
  • npm login して npm publish

まあ、これでも別にいいっちゃいいのですが、いくつか気に入らないところがあり

  • build.sbt の設定と、package.json の設定を別々に管理することになる (version とか)
  • sbt によるビルド成果物のパスをリリーススクリプト側にハードコードしないといけない。
    • 別にいいけど、なんとなくビルド成果物の居場所はsbtが知ってる状態であってほしい。

なんか sbt 側で npm publish をラップしたいな〜と思って適当に github 眺めてると良さげな sbt plugin を見つけました。

github.com

全然ドキュメントない!けどコード読んだらなんか良さそうだったので使ってみた

sbt-npm-package ざっくり

sbt-npm-package がやってくれるのは

  • npm-package ディレクトリを target 以下に作る (target/scala-2.13/npm-package とか)、ここにjsとかpackage.jsonとかを集めてくれる。
  • npmPackageNpmrcnpm-package/.npmrc の生成
    • 中身はデフォルトで //registry.npmjs.org/:_authToken=${NPM_TOKEN}
  • npmPackagePublish で js 成果物を npm にアップロード
    • npm-package/package.json を build.sbt での設定を元に生成
    • ビルド成果物のJSを npm-package/main.js にコピー
    • (デフォルトではプロジェクトルートの) README.mdnpm-package にコピー
    • npm-package ディレクトリ上で npm publish を実行

なので基本的にはこの記事の最初に述べたリリース手順をsbt側に寄せて自動化してくれるというシンプルなもの。

設定しそうな settingKey

sbt-npm-package/NpmPackagePlugin.scala at f72e90581a63841039685371dbbe46e20e6ae6c7 · davenverse/sbt-npm-package · GitHub

settingKey 説明 デフォルト
npmPackageName package.jsonname sbt の project name からいい感じに作られる
npmPackageDescription description
npmPackageVersion version sbtversion が利用される
npmPackageRepository repository git ls-remote --get-url origin
npmPackageREADME アップロードする README.md へのパス README.md
npmPackageStage fullOptJS とか fastOptJS とか指定する FastOptJS

設定にない項目は npmPackageAdditionalNpmConfig で書き加えられる。

npmPackageAdditionalNpmConfig := Map(
   "homepage" -> _root_.io.circe.Json.fromString("https://scalameta.org/")

使用例

例えば

npmPackageName := "scalameta-parsers",
npmPackageDescription := "Library to parse Scala programs",
npmPackageRepository := Some("https://github.com/scalameta/scalameta"),
npmPackageAuthor := "scalameta",
npmPackageLicense := Some("BSD-3-Clause"),
npmPackageKeywords := Seq("scala", "parser"),
npmPackageVersion := "4.6.0",
npmPackageAdditionalNpmConfig := Map(
  "homepage" -> _root_.io.circe.Json.fromString("https://scalameta.org/")
),

こんな感じの設定で npmPackagePublish すると以下のような pakcage.json が作られます。

{
  "name" : "scalameta-parsers",
  "description" : "Library to parse Scala programs",
  "version" : "4.6.0",
  "type" : "commonjs",
  "repository" : {
    "type" : "git",
    "url" : "https://github.com/scalameta/scalameta"
  },
  "author" : "scalameta",
  "license" : "BSD-3-Clause",
  "main" : "main.js",
  "dependencies" : {},
  "devDependencies" : {},
  "keywords" : ["scala", "parser"],
  "homepage" : "https://scalameta.org/"
}

良さそうですね。

あとは repository secret に npm からとってきた access token を NPM_TOKEN として登録して、以下のように npm と sbt のある環境で npmPackageNpmrc -> npmPackagePublish すれば出来上がり

name: Release JS
on:
  push:
    tags: ["*"]
jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-node@v3
        with:
          node-version: "18"
      - uses: actions/checkout@v3
      - uses: olafurpg/setup-scala@v13
      - run: git fetch --unshallow
      - name: Publish
        run: sbt "parsersJS/npmPackageNpmrc; parsersJS/npmPackagePublish"
        env:
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

詳しくはこちら

github.com

ブログに使い方書かないで sbt-npm-package にPRでもすれば良かった気もしてきた。