色々と雑ですがお付き合いください。また、解説は自分のリポジトリのものと少し違います(Linter系バッサリ吹き飛んでます)。
基本情報
- Parcelとは
- 思考停止で(何の設定もなしに)モジュールをバンドルしてくれるマン。
- Hyperappとは
- 超軽量データバインドマン。
- Markdownとは
- Qiita書くときに使うやつ。
- markedとは
- MarkdownからHTMLに変換してくれるモジュール
書いていきます
とりあえず必要なものをyarn add
(npm install
)します。
yarn global add parcel-bundler
yarn add hyperapp marked node-sass
# これらは以下とほぼ同義です
# npm i -g parcel-bundler
# npm i hyperapp marked node-sass
parcel
とhyperapp
は先に書いたとおりです。
-
marked
- Markdown→HTML変換器くん。
-
node-sass
- Sass/SCSS→CSS変換器くん。
index.htmlをつくる
最低限のもののみ、HTML5で省略推奨されているタグは含めていません。
<!DOCTYPE html>
<title>markdown-editor with Hyperapp</title>
<body>
<script src='app.js'></script>
</body>
ここで、app.jsという空ファイルを作っちゃいます。
その後、
parcel index.html
でlocalhost:1234
を開くととりあえずタイトルが「markdown-editor with Hyperapp」の真っ白のWebページが見えました。
Parcelのすごいところは、とりあえずindex.htmlを引数にして実行すればそこからsrcしてるファイルが全て自動でコンパイル&ブラウザ側でライブリロードされる点ですね。
hello Hyperapp
では、app.jsを編集します。
import { h, app } from 'hyperapp'
const state = {
'output': 'hello, Hyperapp'
}
const actions = {
}
const view = (state, actions) => (
<main id='app'>
{state.output}
</main>
)
app(state, actions, view, document.body)
1行目はモジュールのインポートですね。h
はどうやらapp
の実行に必要なようなので一緒に入れてます(一回エラー見ました)。
次に、Hyperappではstate
とactions
とview
とそれらを適用させる場所(app)
が初期化で求められるので、それらを書いてます。
stateは一言で言うと変数です。
actionはそれを編集するためのメソッド、関数を記述します。
viewは表示する中身をほぼそのまんま書いていきます。中身はJSX
記法と呼ばれるもので、{}
で変数の中身を表示できます。
ので、これを保存した頃にはブラウザ側では「hello, Hyperapp」と表示されているはずです。
textareaの中身をリアルタイムで表示する
流れとしては、viewを編集して<textarea>
タグを追加、それが編集されたらactionからメソッドを呼んでstateのoutputをいじって表示する感じです。
で、ハマったのはtextareaの中身をどうやって取得するかです。Vue.jsだと、v-model
とか便利なものがあるんですが、Hyperappに似たようなものがあるかと思ったんだが。
見つかりませんでしたので、生Javascriptで書いてます。誰か知ってたら教えてください。
先程書いたコードの一部を書き換えていくような形で書いていきます。
const view = (state, actions) => (
<main id='app'>
<textarea id='editor' oninput={e => actions.setOutput(document.getElementById('editor').value)} />
<div>{state.output}</div>
</main>
)
oninput
で入力を感知したら、document.getElementById('editor').value
で得られた文字列(=textareaの内容)を引数にactions.setOutput
を実行します。
では、actions.setOutput
を定義します。
const actions = {
setOutput: (input) => state => ({ output: input })
}
アロー関数式=>
を使っているので混乱させてしまったら申し訳ないですが、つまり引数をinput
として扱ってstate.output
を変更するというものです。
この状態で、ブラウザに表示されているtextareaに文字を入れたとき、その内容がそのまま表示されていれば成功です。
textareaの中身でリアルタイムHTMLプレビューする
さっきまでの文字列はあくまで文字列として扱われ、HTMLタグはプレビューできてません。
上で話した通り、モジュール「marked」はMarkdownをHTMLに変換するため、HTMLプレビューが必要でした。
この変更はviewを編集するだけで秒解決です。ただ、Vue.jsで言うところのv-html
のような機能も見当たらなかったので、直書きします。
const view = (state, actions) => (
<main id='app'>
<textarea id='editor' oninput={e => actions.setOutput(document.getElementById('editor').value)} />
<div id='preview' innerHTML={state.output}></div>
</main>
)
innerHTML
に入れたら解決しました。やったぜ。
仕上げの時間だ。Markdownプレビューしますよ
さて、もうここまでくるとoutputの中にmarkdownから変換されたHTMLを代入するだけですね。
上に書いたとおり、Markdown→HTML変換器くんのmarkedを使います。
まずmarkedのimport文の追加。
import marked from 'marked'
で、actionの編集。
const actions = {
setOutput: (input) => state => ({ output: marked(input) })
}
marked超便利。marked超便利。marked超便利。
はい、これでとりあえず終了ですね。
見栄えをどうにかする
これに関しては最初にnode-sass
を導入してるのでSCSSやSass、もしくはCSSを書いて下さい。僕の場合はこんな感じでした。
今回はJavascriptの解説だったので、あえてこの解説は省きます。
style.sass
html, body
height: 100%
width: 100%
margin: 0
#app
display: flex
height: 100%
textarea, #preview
flex: 1 1 0
overflow-y: scroll
textarea
padding: 1em
font-size: 12px
background-color: #eee
line-height: 1.5em
font-family: courier, monospace
border: 0
#preview
padding: 1em
pre
padding: 15px
background-color: #282c34
color: #EEE
margin-right: 10px
@media print
textarea
display: none
#preview
overflow-y: visible
で、それをimportします。
import './style.sass'
おまけ:Highlight.jsでcodeをいい感じに表示する
Highlight.jsはcodeタグ内の各種コードをいい感じの色にしてくれるものです。
yarn add(npm install)
yarn add highlight.js
import highlight from 'highlight.js'
import 'highlight.js/styles/atom-one-dark.css'
marked.setOptions({
highlight: function (code, lang) {
return highlight.highlightAuto(code, [lang]).value
}
})
.hljs
all: unset
以上です。お疲れ様でした。
一分説明が雑になってしまったので申し訳ないですが、以上になります。
Parcelは設定ファイルを作成しなくて良い、Hyperappは非常に少ないコードで書けるというそれぞれの強みが有ります。
逆に、これらは細かい設定が出来ない、複雑なものが作りにくいという弱みに直結しますが、使えるところでは使えるということを体感して頂けたら幸いです。
あ、Parcelで静的データ書き出ししちゃいましょう。
parcel build src/index.pug --public-url ./
これでdist
の中に公開できる状態のデータが生成されているはず。
はやい。
かんたん。
Parcelだいすき。
何か質問、ご指摘等有りましたらなんでもお願いします。
では。
修正・補足
- 180322
- parcel-bundlerをグローバルインストールに変更しました。グローバルを汚したくない人はnpm scriptsをよしなに書いて下さい。