Skip to main content

ImgurImgur

Atomが完全に死んだので、VSCodeに移行しました。 Atomを諦めていない方は去年書いたSetup Atom | TSEI.JPをご覧ください。


Github


Utils


Tools


Highlight


Design


Markdown



Frontend

JS/TS


Browser


Backend



REF


  1. hello

lerna is dead

最近npmや、yarn周りでエラーが起きるのですが、 [email protected] (2021-02-10)がリリースされてからメンテナンスされていません。 lernaはyarn2以上では動かないことが多いらしく、yarnのバージョンを怖くて上げられないでいました。

メンテナーの方のTweetやプロファイルによると、OSSをやめてしまったらしいです。 (代替案を見ると、他がこぞって作っているので、やめたくなるのもわかる気がします。) なので、移行先を検討します。

Front-End Engineer, burned out OSS maintainer, and Oxford comma enthusiast. He/him. Black Lives Matter.

未だに多くのオープンソースがlernaを使っていますが、Issue #2703によると、 babelはforkして使ってたlernaをやめ、yarnで管理するらしいです。

TIL that babel replaced lerna with a custom yarn plugin to manage releases in PR babel/babel#12138 in Oct 2020.

@changesets/cli vs @microsoft/rush vs @nrwl/workspace vs turbo

npm workspace

yarn workspace や npm workspace のみで monorepo を管理する方法です。

changesets

Atlassian社謹製です。Issue #2703で言及されていました。 もとはAtrassionがsemantic-releaseからforkしたのを、lernaベースに作りかえるらしいです。

rushstack

Microsoft社謹製です。ChangeLogがいい感じになるらしいです。

turborepo

vercel社謹製です。いい感じにしてくれるらしいです。

nx

nrwl社謹製です。ほかもいい感じにしてくれるらしいです。

  • npx [email protected] --preset=coreではじめられます。
  • npx add-nx-to-monorepoで既存のrepoにも追加できます。

結論

monorepoにもtoolchainの栄枯盛衰が早くて悲しくなるので、 とりあえず lerna ではじめ、 そのうちlernaが完全にダメになれば changesets、 ものレポの規模が大きくなれば、Bazel でそろえる形にしました。 Googleを信じろ、 Believe Google

情念

Frontend
  • SEO (Search Engine Optimization) ぐるぐる検索で出やすくする。
  • SPA (Single Page App) JSからHtmlをつくる。
  • CSR (Single Page App) スマホ側でJSからHtmlをつくる。
  • SSG (Static Site Generator) ビルド毎にJSからHtmlをつくる。
  • SSR (Server Side Rendering) サーバー側でJSからHtmlをつくる。
  • ISR (Incremental Static Regeneration) リクエスト毎にJSから次のHtmlをつくる。
Network
  • CDN (Content Delivery Network) パソコンをいっぱい使える。
  • CMS (Content Management System) 簡単にサイトを作れる系。
  • DNS (Domain Name System) URLに文字を打つとサイトが見れる。
  • RestAPI: URLで必要なデータだけ送ったり送られたりする。
Backend
  • IaaS (Infrastructure as a Service) パソコンごと貸してくれる。
  • PaaS (Platform as a Service) データベースなど、ソフトごと貸してくれる。
  • SaaS (Software as a Service) Gメールなど、用意されたアプリを貸してくれる
  • SQL (Structured Query Language) データベースのための言語
  • ORM (Object-Relational Mapping): SQLなしでデータベースをつかう。

Tool

  • Git: よくつかう。
  • Github: コードがいっぱいある。
  • Docker: 環境構築しなくて済む。
  • Kubernetes: 勝手にパソコンを大きくしてくれる。

Lang

  • Rust: 人気。
  • Ruby: 日本で人気。
  • Python(py): 読みやすい。
  • C/C++(c, cc, cpp): 読みにくい。
  • C#/F: Windowsあぷりつくれる。
  • Swift: iOSあぷりつくれる。
  • Kotlin: Androidあぷりつくれる。
  • Dart: あぷりつくれる。
  • Java: 何でもつくれる。
  • JavaScript: よくない。
  • ActionScript: 人気だった。
  • CoffeeScript: 人気だった。
  • TypeScript: 人気。
  • CloujureScript: 人気になる。

Markup

  • HTML: Webサイト作れる。
  • CSS: Webデザイン作れる。
  • Scss: CSSの上位互換。
  • Sass: CSSの上位互換。
  • Markdown: なんでもつくれる。
  • TeX: 大学で強要される。?

フレームワーク

Frontend
  • jQuery: Webアプリ作れる(ようになった)
  • Angular.js: Google謹製で人気だった。
  • React.js: Facebook謹製で人気。
  • Vue.js: 日本で人気。
Backend
  • Ruby on Rails: Rubyで動くサーバー。
  • Django.py: Pythonで動くサーバー。
  • Node.js: パソコンでJSが動く。
  • Deno.js: Node.jsと同じ人が作った。
  • Express
  • Fastify
Fullstack
  • Remix.js: 良い。
  • Next.js: バックエンドが動く
  • Nuxt.js: Next.jsのVue.js版。
  • Nest.js: Next.jsのなんでも版?

Server

  • MySQL: Myさんのお父さんが作った。
  • PostgreSQL: ぞうさんが作った。
  • MongoDB: NoSQL。
  • GraphQL: 難しそう。
  • SQLite: エスキューエルアイト。
  • Redis: レッドアイエス。
  • NGINX: ネギックス。❌ッンギンックス。

Service

  • Express Server
  • Architect (AWS Lambda)
  • Fly.io
  • Netlify
  • Vercel
  • Cloudflare Pages
  • Cloudflare Workers
  • Deno (experimental)

class based React.js hooks

REF: [1]

Reactで複雑な処理を加えたとき、useMemo, useCallbackだらけになったり、 useRef, xxxRef.currentだらけになり、読みにくいコードになることがあります。 クラスベースで、Ctrlクラスを作成し、hookから操作します。 例として、useDelay.tsを定義します。 このフックは、実行を少し遅らせることで、重い処理などが重複するのを防ぎます。

import React from 'react'

class Ctrl {
listener = () => {};
callback = () => {};
timeStamp = 1000;

apply(callback = () => {}, timeStamp = 1000) {
this.callback = callback;
this.timeStamp = timeStamp;
return this.delay.bind(this);
}

delay(...args) {
const timeout = window.setTimeout(this.callback, this.timeStamp, ...args);
this.listener();
this.listener = () => void window.clearTimeout(timeout);
}
}

export default function $(callback = () => {}, timeStamp = 1000) {
const [ctrl] = React.useState(() => new Ctrl());
React.useEffect(() => ctrl.listener, [ctrl]);
return ctrl.apply(callback, timeStamp);
}

applyはstateが変化するごとにが実行され、状態や返す関数を更新しています。 delayは実行毎にlistenerをリセットし、時間がたつとcallbackを実行します。 次のアプリでは、文字の打ち込みが終わった1秒ごとに、callbackが動作します。 codesandbox でも試すことができます。

import React from "react";
import ReactDOM from "react-dom";
import $ from './useDelay';

function App() {
const [state, set] = React.useState`⚡Lets write here⚡`;
return (
<>
{ state }
<input
onKeyDown={(e) => set`🐛Now writing🐛`}
onKeyUp={$((e) => set`✅Completed✅`, 1000)}
/>
</>
);
}

ReactDOM.render(<App />, document.getElementById`root`);

ProjectedMaterial

REF: [[1], [2], [3], [4]]

Three.jsで、指定したカメラから見た光景を、TextureにするMaterialです。 また、ProjectedMaterialでは、envMapなども指定できたりします。 一つ注意なのが、project()を一度実行する必要があります。

import React from 'react';
import { extend } from '@react-three/fiber'
import ProjectedMaterial from "three-projected-material";

extend({ ProjectedMaterial });

function Mesh () {
const ref = React.useRef()
React.useEffect(() => void ref.current.material.project?.(ref.current), []);
return (
<mesh ref={ref}>
<projectedMaterial args={[{texture, camera}]} />
<boxGeometry args={[1, 1, 1]} />
</mesh>
)
}

web midi api

MIDIAccessについて

まず、flagsからWebMIDIAPIを有効にし、browserを再起動します。 次に、サーバーサイドや非対応の対策nativeRmaを用意します。

const options = { sysex: true, software: true }
const supported =
typeof navigator !== 'undefined' && // @ts-ignore
typeof navigator.requestMIDIAccess === 'function'
const nativeRma = () => {
if (!supported) console.warn('Cannot supported Web MIDI API') // @ts-ignore
else return navigator.requestMIDIAccess(options)
}

次のようにするとIllegal invocationエラーが起きます。 (ネイティブのコードなので、他に代入できません。)

nativeRma = navigator.requestMMIDIAccess
// TypeError: Failed to execute 'requestMIDIAccess' on 'Navigator': Illegal invocation

Promiseで取得できるMIDIAccessから、各MIDIPortを操作できます。

const change = (access: MIDIAccess) => {}
const error = console.error
nativeRma()?.then(change, error)

onstatechangeについて

change内でMIDIAccess.onstatechangeを指定すると、 portが変化するごとに実行してくれます。 onstatechangeMIDIPortからも指定できます。

MIDIAccess {
onstatechange: (e: MIDIConnectionEvent) => void
inputs: maplike <DOMString, MIDIInput>;
outputs: maplike <DOMString, MIDIInput>;
sysexEnabled: boolean
}

MIDIPort {
onstatechange: (e: MIDIConnectionEvent) => void
Promise<MIDIPort> open
Promize<MIDIPort> close
}

maplikeなので、clear(), delete(), set()が使用できません。 maplikeのkey名が長く、get(), has()も使いにくいです。 ですので、size, keys(), values(), entries(), forEach()を主に使います。

onmidimessage, sendについて

MIDIInput.onmidimessageからデータを受け取り、MIDIOutput.sendからデータを送信します。 両方ともMIDIPortを継承しているため、onstatechangeを指定することもできます。

MIDIInput extends MIDIPort {
onmidimessage: (e: MIDIMessageEvent) => void
}

MIDIOutput extends MIDIPort {
send (data, timestamp) => void
clear () => void
}

Eventについて

REF

onstatechangeの引数のMIDIConnectionEventと, onmidimessageの引数のMIDIMessageEventEventから継承されているので、 addEventListennerで関数を登録したり timeStampで時間を計測したりできます。

interface MIDIConnectionEvent extends Event {
target: MIDIAccess
port: MIDIPort
}

interface MIDIMessageEvent extends Event {
data: Unit8Array
}

random color

REF : [1, 2, 3]

stackoverflowのコードを jsbench.meでベンチマークした結果です。 (markdownの関係で、\| となっていますが、正しくは |です)

.toStringScore
'#' + (Math.random() * 0xffffff \| 0).toString(16)Fastest💪
'#' + (Math.random() * (1<<24) \| 0).toString(16)Fastest💪
'#' + (Math.random() * (1<<24) << 0).toString(16)+1.24%👍
'#' + parseInt(Math.random() * 0xffffff).toString(16)+2.25%👍
'#' + Math.floor(Math.random() * (1<<24)).toString(16)Fastest💪
'#' + Math.round(Math.random() * 0xffffff).toString(16)+7.51%👍
.sliceScore
'#' + Math.random().toString(16).slice(-6)+53.96%🐢
'#' + Math.random().toString(16).slice(2,8)+ 52.54%🐢
'#' + (Math.random().toString(16)+'00000').slice(2,8)+67.83%🐢
.substrScore
'#' + Math.random().toString(16).substring(-6)+50.28%🐢
'#' + (Math.random().toString(16) + "000000").substring(2,8)+67.44%🐢
'#' + ((1<<24)*(Math.random()+1) \| 0).toString(16).substr(1)+15.7%👍
'#' + (((1+Math.random())*(1<<24) \| 0).toString(16)).substr(-6)+15.91%👍
'#' + (0x1000000+Math.random()*0xffffff).toString(16).substr(1,6)+66.46%🐢
otherScore
'#' + Math.round((0x1000000 + 0xffffff * Math.random())).toString(16).slice(1)+20.36%👍
"#xxxxxx".replace(/x/g, y=>(Math.random()*16\|0).toString(16))+85.52%🐢
rgb(${[1,2,3].map(x => Math.random()*256\|0)})+69.62%🐢
hsla(${Math.random() * 360}, 100%, 50%, 1)+ 57.79%🐢
["r", "g", "b"].reduce(r => r + ("0" + ~~(Math.random()*256).toString(16)).slice(-2), "#")+89.79%🐢

range function in JavaScript

lodashを参考に,よく使うrangeをより早く実装してみました。

function range (n=0) {
const ret = new Array(n)
for (;n--;) ret[n] = n
return ret
}

いくつかのショートハンドもありますが、 keys()を使うと90%近くも遅くなるらしいです。 また、nを大きくしたところ、map()でも90%ほど遅くなりました。

range(Math.random() * 100 << 0) // Fastest 💪
keys(Math.random() * 100 << 0) // 93% slower 🐢
map(Math.random() * 100 << 0) // 60% slower 🐢
function keys (n=0) {
return [...Array(n).keys()]
}

function map(n=0) {
return [...Array(n)].map((_, i) => i)
}

Markdown tips

basic

MDHtmlResult
# HI<h1>HI</h1>

HI

## HI<h2>HI</h2>

HI

### HI<h3>HI</h3>

HI

#### HI<h4>HI</h4>

HI

##### HI<h5>HI</h5>
HI
###### HI<h6>HI</h6>
HI
_HI_<em>HI</em>HI
__HI__<strong>HI</strong>HI
~~HI~~HI
> HI<blockquote></blockquote>
HI
HI
<code>HI</code>HI
x<u>HI</u>HI
x<mark>HI</mark>HI
x<small>HI</small>HI
x<ruby><rt>HI</rt></ruby>HI
x<kbd>HI</kbd>HI

[alt](href) | <a /> ![alt](href) | <img/>

[this is link][LINK]
[this is mail][MAIL]

[LINK]: http://google.com
[MAIL]: [email protected]

[link](
https://tsei.jp)

[![alt](
https://tsei.jp)](
https://tsei.jp)

list

MdResult
- 1
- 2
  • 1
  • 2
1. 1
1. 2
  1. 1
  2. 2
| 1 | 2 |
|:- |:- |
| 3 | 4 |
12
34

mark up

<td>
<details>
<summary>Details</summary>
Something small enough to escape casual notice.
</details>
</td>
Details
Something small enough to escape casual notice.
<ruby>
<rp></rp><rt>Kan</rt><rp></rp>
<rp></rp><rt>ji</rt><rp></rp>
</ruby>
Kanji

Hack

img width

<img width=100 href=""/>
|<img width="100"/>|<img width="500"/>|<img width="400"/>|  
|:-|:-|:-|
| 1 | 2 | 3
or

<table>
<tr>
<th width="100"></th>
<th width="500"></th>
<th width="400"></th>
</tr>
</table>

<div  align="center">
<strong>
<kbd>
<h3>
<a href="#"><img width="100"/></a>
<a href="#">GET</a>
<a href="#"><img width="100"/></a>
</h3>
</kbd>
<kbd>
<h3>
<a href="#api"><img width="100"/></a>
<a href="#api">API</a>
<a href="#api"><img width="100"/></a>
</h3>
</kbd>
</strong>
</div>

JavaScript tips

Shorthand

Boolean(0)!!0
String(3.14)3.14 + ""
Number("3.14")+ "3.14"
Math.floor(3.14)~~3.14 or
3.14 << 0
undefinedvoid 0
100001e4

flatMap

result = []
for (v of array)
if (v !== 0)
array.push(1/v)
  • array.map(v => v !== 0 && 1/v).filter(v => v)
  • array.flatMap(v => v === 0? []: 1/v)

Math

const {sin, asin} = Math
[0, 1, 2].map(sin).map(asin)

template literal

function upper(args) {
return args[0].toUpperCase()
}
const text = upper`hi` // HI

functional object

const hello = () => 'HELLO'
hello.world = () => 'WORLD'
hello() // HELLO
hello.world() // WORLD

assignment

let t = -1,
dt = 100 - (~t? t: (t = 0))
console.log(t) // 0