@peccul is peccu

(love peccu '(emacs lisp cat outdoor bicycle mac linux coffee))

ES2019の実装QuickJSを試せるDockerイメージを作った

QuickJSというES2019の実装が出てきたと見かけたので Dockerで使えるようにしてみた。

bellard.org

alpineイメージでMulti stageビルドして、qjsなど成果物だけを設置したalpineイメージになっている。

Docker hub上では15MBほど、ローカルで確認すると40MB程度。

peccu/qjs - Docker Hub

qjsを直接叩く例

$ docker run -it --rm --name qjs peccu/qjs qjs
QuickJS - Type "\h" for help
qjs > console.log("Hello World");
Hello World
undefined
qjs >

shを叩く例

/workが作業ディレクトリになってるのでそこをボリュームで指定してあげれば使える。

$ docker run -it -v $PWD:/work --rm --name qjs peccu/qjs
/work # qjs -m /quickjs/examples/hello_module.js
Hello World
fib(10)= 55
/work # 

QuickJSに含まれていたdoc/examples/ディレクトリを/quickjsに展開している。

qjs, qjsc, run-test262, qjsbn, qjsbnc, run-test262-bn のコマンドにパスが通っている。

fzf便利

fzf: fuzzy finder

使い方を忘れる。プレビュー付きで絞り込み検索できるの素敵。

https://raw.githubusercontent.com/bluz71/misc-binaries/master/blog/git_log_browser.png

ES6で動的に親クラスを指定する

引数に応じて親クラスを切り替えたいことがあって調べて、Dynamic super classes (extends) in ES6 – MikeDoesWeb が出てきたので試した。

おそらく私はmix-inみたいなことをしたかったのだと思う。

サンプルコードとそれのテスト(使い方の例になると思う)はGitHubに置いた。

github.com

解決法の解説/概要

クラスを直接定義するのではなく、関数スコープ内で定義することで解決していた。

実際に私がやりたかったのはNode.jsで動くならfsを使うクラスを継承して、ブラウザで動くならBrowserFSを使うクラスを継承したかった。 外からみると同じAPIにしたかったので、環境か引数によって必要なバックエンドのクラスを切り替えてテストしたかった。

以下GitHubに置いた解決策の抜粋。

// fsを使うクラス
export class FS {
  constructor(config){
  }
}

// BrowserFSを使うクラス
export class BrowserFS {
  constructor(config){
  }
}

// fallbackクラス
export class DefaultClass {
  constructor(config){
  }
};

// 外からはこの擬似クラス(実態は関数)を使う
const Dynamic = function(config = {}){
  if(!new.target){
    throw "Uncaught TypeError: Class constructor Dynamic cannot be invoked without 'new'";
  }
  // Dynamicというクラスを引数に応じて定義する

  if(config.backend === 'fs'){
    // FSを継承するパターン
    class Dynamic extends FS {
      constructor(config){
      }
    };
    return new Dynamic(config);
  }

  if(config.backend === 'browserfs'){
    // BrowserFSを継承するパターン
    class Dynamic extends BrowserFS {
      constructor(config){
      }
    };
    return new Dynamic(config);
  }
  // fallback
  return new DefaultClass(config);
};
export default Dynamic;

es6-dynamic-class-extends/dynamic.js at master · peccu/es6-dynamic-class-extends · GitHub

使用法はテストコードでイメージできるかと。 (Jest利用、同じく抜粋)

Dynamicはクラスではなく関数なので、instanceof Dynamic はfalseとなる。

import {default as Dynamic, FS, BrowserFS, DefaultClass} from './dynamic';

describe('Dynamically switching parent class', () => {
  test('non specified class', () => {
    let target = new Dynamic();
    expect(target).toBeInstanceOf(DefaultClass);
  });
  test('extends FS', () => {
    let target = new Dynamic({backend: 'fs'});
    expect(target).toBeInstanceOf(FS);
  });
  test('extends BrowserFS', () => {
    let target = new Dynamic({backend: 'browserfs'});
    expect(target).toBeInstanceOf(BrowserFS);
  });
});

es6-dynamic-class-extends/dynamic.test.js at master · peccu/es6-dynamic-class-extends · GitHub

c.f.

github.com

environment

  • .babelrc
{
  "presets": ["@babel/preset-env"],
  "plugins": [
    [
      "@babel/plugin-transform-runtime",
      {
        "regenerator": true
      }
    ]
  ]
}
  • package.json
...
  "scripts": {
    "test": "jest"
  },
  "devDependencies": {
    "@babel/core": "^7.2.2",
    "@babel/plugin-transform-runtime": "^7.2.0",
    "@babel/preset-env": "^7.2.3",
    "@babel/runtime": "^7.2.0",
    "babel-core": "^7.0.0-bridge.0",
    "babel-jest": "^23.6.0",
    "jest": "^23.6.0"
  },
...

git remoteにssh接続するときに秘密鍵を指定する

ssh接続するコマンドを環境変数に指定すればよい。

GIT_SSH_COMMAND="ssh -i /path/to/id_rsa-for-remote -F /dev/null" git ...

... の部分は clone なり push origin branch なりgitサブコマンドを指定する。