prettier-on-scrapboxの紹介
自己紹介
mizdra.icon mizdra (みずどら)
電気通信大学 3年
好きなこと
JavaScript/TypeScript
Webアプリ開発
ゆゆ式
近状
Slack向けの自分のEmojiを作った
:mizdra_static:
https://gyazo.com/de939e85b38c7a2702665d3402cf5d66
:mizdra_animation:
https://gyazo.com/61ab8ee584e2de1612394ad7f3b09b1a
:mizdra_animation_highspeed:
https://gyazo.com/a258c2a21a25d101c1dc9ef714ef562a
:kyomudra:
https://gyazo.com/bdf594b09d786bb58535db6ebce402f5
:mizdra_animation_rolling:
https://gyazo.com/385c45e6bec59ad2a1d60437de13df13
本題へ
本日のお題
prettier-on-scrapbox
🙋♀️🙋♀️🙋♀️Prettier知ってる人🙋♀️🙋♀️🙋♀️
🙋♂️🙋♂️🙋♂️Scrapbox知ってる人🙋♂️🙋♂️🙋♂️
Prettier
Code Formatter
インデントやクオテーション, 末尾カンマなどのスタイルに関する面倒を見てくれる
サポートしている言語が豊富
JS / JSX / Angular Vue / Flow / TypeScript
HTML / Markdown / GraphQL
MarkdownをPrettierするとこんな感じ
https://gyazo.com/ea80ad503b3b82a496a2283d395c3564
一方, Scrapbox
次世代コラボレーションツール / Wiki
今使ってるスライドもScrapboxで作ってる
Scrapboxのコードブロック
code:言語名もしくはcode:ファイル名から1段字下げしたブロックがシンタックスハイライトされます
技術的なこと書く時に便利 mizdra.icon
コードフォーマッタが付いてないので, いつも人力でスタイルを修正している
Prettierでよしなにしたい /icons/party_parrot.icon
UserScriptで動かせないかな…
という訳で作った
使い方
UserScriptに以下を追加
code:script.js
import '/api/code/mizdra/prettier-on-scrapbox/script.js'
window.userPrettierConfig = {
trailingComma: 'all',
tabWidth: 2,
semi: false,
singleQuote: true,
arrowParens: 'always',
proseWrap: 'never',
}
プレビュー
https://gyazo.com/112012f88d1daaa0c451e5e5baafe317
Playground
code:*で指定されている言語に合わせてフォーマットしてくれる.
code:get-started.js
const message = "hello"
console.log(message);
foo(reallyLongArg(), omgSoManyParameters(), IShouldRefactorThis(), isThereSeriouslyAnotherOne());
プラグインを追加すれば, あらゆる言語でフォーマットできる.
code:ts
const add=(a:number,b:number)=>a+b
code:graphql
type Query { currentUser: User! }
type User {
id: ID!
name: String!
}
リストでネストしていたり...
code:a.js
"(*゚▽゚)ノ";;;;
コードブロックが連続していてもOK
code:b.js
"⊂( *·ω· )⊃";;;;
code:c.js
"|ω·)ミテマスヨ";;;;
範囲選択でまとめてフォーマットできる
How It Works
公式でブラウザ上で動くstandalone版Prettierが提供されている
code:standalone.html
<script type="text/javascript">
prettier.format("query { }", { parser: "graphql", plugins: prettierPlugins });
</script>
これをUserScript上で読み込めば動くのでは??? mizdra.icon*3
How It Works
試してみる
code:script.js
const result = prettier.format('query { }', {
parser: 'graphql',
plugins: prettierPlugins,
})
console.log(result)
https://gyazo.com/7c623328b7565256485da04f08a55ad4
ドメインにより読み込めるスクリプトが制限されていて無理だった💥
How It Works
Scrapbox上にそのままソースコード貼ればイケるのでは?
scrapbox.ioで配信されるので読み込めるハズ
とりあえずそのまま貼り付けてみる
https://gyazo.com/95e825e34ce3a21911963454832af111
巨大なページが誕生
全部で3万行
minifyしてないので当然といえば当然
読み込みに2分くらい掛かる
ServiceWorkerで読み込み処理が行われるので, scrapbox.ioドメインのページを開いているタブ全てがフリーズする
/icons/どうして.icon*15
ところでSW<=>サーバ間の同期処理に時間が掛かってWeak Connectionとして検知されてるの面白い
ちなみにこれでも動かない
https://gyazo.com/eaa0b7676c8ff2eae66f8796820e3e9c
Classic ScriptをModule Script (ES2015 Modulesで書かれたモジュール) として読み込んでいるため
<script src="script.js"></script>で読み込めるのがClassic Script
一方import module from 'script.js'で読み込めるのはModule Script
standalone.jsはClassic Scriptなので, UserScriptから利用するにはModule Scriptなstandalone.jsを用意する必要がある
ちなみに公式ではModule Script版standalone.jsは用意されてない
そんな…
という訳で
自作しましょう
code:build.sh
$ cd prettier
$ yarn
$ yarn run build
$ ls dist/*.js
dist/bin-prettier.js
dist/index.js
dist/parser-angular.js
dist/parser-babylon.js
dist/parser-flow.js
dist/parser-glimmer.js
dist/parser-graphql.js
dist/parser-html.js
dist/parser-markdown.js
dist/parser-postcss.js
dist/parser-typescript.js
dist/parser-yaml.js
dist/standalone.js
dist/third-party.js
minifyされたModule Scriptが生成される
N度目の正直
これをUserScriptにコピペする
code:script.js
import prettier from '/api/code/mizdra/prettier%2Fstandalone/script.js'
import graphqlParser from '/api/code/mizdra/prettier%2Fparser-graphql/script.js'
const result = prettier.format('query { }', {
parser: 'graphql',
})
console.log(result)
動いた🎉
次のステップ
Scrapboxからコードブロックを抽出し, prettier.formatで変換したい
UserScript向けのScrapbox内部APIを利用する
scrapbox.PopupMenu.addButtonで範囲選択した時にポップアップされるアクションボタンを追加できる
https://gyazo.com/ca4293247744e8c325ea350efd5c6221
code:api.js
scrapbox.PopupMenu.addButton({
title: 'Format',
onClick: (oldText) => {
const newText = format(oldText)
return newText
},
onClick: 引数で選択中の文字列を受け取り, 戻り値で変換後の文字列を返せる
コードブロックの検知
Scrapboxのテキスト表現
code:text.sb
ルートアイテム.
code:script.js
console.log('hello')
console.log('world')
リストアイテム a-1
code:javascript
console.log('!!!')
リストアイテム a-2
リストアイテム b-1
リストアイテム b-2
これをScrapboxで見るとこうなる
ルートアイテム.
code:script.js
console.log('hello')
console.log('world')
リストアイテム a-1
code:javascript
console.log('!!!')
リストアイテム a-2
リストアイテム b-1
リストアイテム b-2
取った戦略
テキスト表現をコードブロックと非コードブロックの2種類のNodeにパースする専用のパーサを書いた
https://gyazo.com/803375b340531cd827a1def44fe6f80e
Nodeにはコードブロックのヘッダ (code:*の部分) から推定された言語名を付加している
課題
サポート対象の言語が限られている
現状 JavaScript / TypeScript / GraphQL のみサポート
window.userPrettierConfigで設定を渡していてやんちゃ
code:js
import graphqlParser from './parser-graphql'
import prettierOnScrapbox from './prettier-on-scrapbox'
prettierOnScrapbox.init({
parsers: [
{
parser: 'typescript',
codeBlockTitles: [
/^typescript$/,
/^ts$/,
/^tsx$/,
/*.ts$/,
/*.tsx$/,
],
},
{
parser: 'graphql',
codeBlockTitles: [
/^graphql$/,
/^gql$/,
/*.graphql$/,
/*.gql$/,
],
},
],
prettierConfig: {
trailingComma: 'all',
tabWidth: 2,
semi: false,
singleQuote: true,
arrowParens: 'always',
proseWrap: 'never',
},
})
みたいにモジュール指向で書きたい🙃
巨大ページ作るのやめたい
UserScriptからunpkg.comで配信されているスクリプト読み込めるようにならないかな…