npm scripts で Parcel を再現する

会社の同僚の事業にインターンに行く機会があり、小規模なWebサイトをつくる際に、[Parcel](https://parceljs.org/)を使うのをやめてnpm  scriptsを使ってだいたい同等のことができる環境を作りました。


## Parcelの問題点

ParcelはSPA（シングルページアプリケーション）を作るには、ほとんど設定いらずで手軽。
最初、parcelを使ってpug + sassでサイト構築していました。
ただ、いわゆる複数のページのある通常のサイトをつくるにはいくつか問題があると感じました。


- #### 共通化できるはずのCSSやJavascriptがページ毎になってしまう
    parcelはキャッシュ解除のためファイル名に毎回異なるハッシュをつけるため
    最近、--no-content-hashというオプションもできたが、ファイル名から生成したハッシュをつける若干謎仕様になっている

- #### parcelはリンク先のhtmlも解析してビルドする
    複数ページを作ってリンクしだすと、どこでエラーが起きてるのわかりにくい
    ```baseUrl + ’/hogehoge.html’```
    とpug内に変数をつくっていちいち逃げていた

- #### サブディレクトリが切れない
    すべて同じ階層なら問題ないがサブディレクトリにした途端
    ```include header.pug```
    としていたところで、includeの起点がサブディレクトリからになるので、リンクや画像のパスが通らなくてビルドできなくなる

もともとSPAを作る用途のものだと思うので、しょうがないのですが、結局、後処理が必要になり、最初は楽だけど後でけっこう苦労します。
サイト制作のワークフローとしてはむしろ手間がかかってる印象でした。

そこでnpm scriptsでparcelをだいたい再現しつつ、素直に書き出せる環境を作ってみることにしました。



## 基本方針


- pug + sass
- CSSは1個のみ
- Javascriptはビルドしない
- srcフォルダにあるもの変換してbuildフォルダに書き出す
- assetsフォルダにあるものはbuildフォルダへコピー
- gulpとかgrunt、webpackは使わない。なるべく密結合を避ける。
- npm scriptsでやる


## 開発環境


    node --version
    v10.16.0
    
    npm --version
    6.12.0



## 成果物

https://github.com/deguchi/LooselyTemplate



## ディレクトリ説明

/build/
公開用のファイルの書き出しフォルダ

/src/
ビルドのもとになるpugの保存フォルダ
サブディレクトリを作ると、それも書き出せる

/src/index.sass
sassファイル
小規模なサイトを想定しているのと単純化のため、CSSファイルは1個
この階層に置いているのは、pugからの相対位置を公開版と合わせるため

/src/sass/
index.sassにimportするsassファイルを置くフォルダ


## npm scripts


    "scripts": {
      "start": "npx npm-run-all clean build:sass build:autoprefixer build:copy:assets watch -p",
      "clean": "npx rimraf build",
      "watch": "concurrently \"npm run watch:pug\" \"npm run watch:sass\" \"npm run watch:browser-sync\"",
      "watch:browser-sync": "npx browser-sync start --config ./bs-config.js",
      "watch:sass": "npm run build:sass -- --watch",
      "watch:sass2": "npx chokidar \"./src/**/*.sass\" --command \"npm run build:sass && npm run build:autoprefixer\"",
      "watch:pug": "npm run build:pug -- --watch --pretty",
      "build": "npx npm-run-all clean build:** -s",
      "build:sass": "npx node-sass ./src/index.sass ./build/index.css --output-style compressed",
      "build:autoprefixer": "npx postcss ./build/index.css -o ./build/index.css --config ./postcss.config.js",
      "build:pug": "npx pug -O pug_env.js src/ --out ./build/",
      "build:copy:assets": "npx cpx \"src/assets/**/*\" build/assets/",
      "test": "echo \"Error: no test specified\" && exit 1"
    },




## 各コマンドの解説


    "build": "npx npm-run-all clean build:** -s",

[npx](https://dev.classmethod.jp/node-js/node-npm-npx-getting-started/)

ローカルにインストールしたnpmのCLIコマンドを実行してくれる


> npxコマンドをたたくと次の順番でコマンドを探します。
            1. ローカルパッケージ（node_modules/.bin）
            2. 環境変数PATH
            3. npmレジストリ

[npm-run-all](https://github.com/mysticatea/npm-run-all)

npm scriptsのコマンドを、逐次・並列実行できるコマンド
build: と先頭につけたコマンドを逐次実行している



    "build:sass": "npx node-sass ./src/index.sass ./build/index.css --output-style compressed",

sassをコンパイルし、build/index.cssへ書き出し



    "build:autoprefixer": "npx postcss ./build/index.css -o ./build/index.css --config ./postcss.config.js",

[postcss-cli](https://github.com/postcss/postcss-cli)

build/index.cssにベンダープレフィックスや、CSSグリッドをIE対応で書き出すなどの後処理を行う
watch時には、処理が重いので外してある

https://github.com/deguchi/template/blob/master/postcss.config.js
postcss.config.jsにCSSグリッドをIE対応で書き出すオプションを追加してある


    "build:pug": "npx pug -O pug_env.js src/ --out ./build/",

[pug-cli](https://github.com/pugjs/pug/tree/master/packages/pug)

pugをhtmlに変換してbuildフォルダに書き出している

-O オプションは蛇足だがpug_env.jsを以下のように書いて

    module.exports = { env: 'production' };

pug内に変数を注入することができるオプション
環境変数でproduction時だけ変更するよう処理をpugで書くことが可能。

この処理はビルド時に走るので、[contentful](https://www.contentful.com/)などのJSONを吐くCMSのJSONを取得して注入してブログ部分を構築するスクリプトを書き、CMSの投稿に合わせて、[netlify](https://www.netlify.com/)でビルドさせて公開＝WordPress不要なサイトも構築可能かもしれない。
クライアントワークの場合、UIが英語ということのほうがネックかもしれないけれど。。


    "build:copy:assets": "npx cpx \"src/assets/**/*\" build/assets/",

[cpx](https://github.com/mysticatea/cpx)

src/assetsフォルダに置いたファイルを、build/assets以下にコピーする



    "watch:sass": "npm run build:sass -- --watch",

build:sassをwatchするオプションつけて実行


    "watch:sass2": "npx chokidar \"./src/**/*.sass\" --command \"npm run build:sass && npm run build:autoprefixer\"",

これは使っていないが、autoprefixerの処理をwatch時も走らせたい場合はこちらを使うとよい


    "watch:pug": "npm run build:pug -- --watch --pretty",

build:pugをwatchするオプションつけて実行
開発時はデバッグしやすいので、—prettyオプションもつけてある


    "watch:browser-sync": "npx browser-sync start --config ./bs-config.js",

[browser-sync](https://www.browsersync.io/)

開発用のWebサーバーを立ち上げる

https://github.com/deguchi/template/blob/master/bs-config.js

browser-sync initで作成したファイルにオプションを指定してある


    "watch": "concurrently \"npm run watch:pug\" \"npm run watch:sass\" \"npm run watch:browser-sync\"",

[concurrently](https://github.com/kimmobrunfeldt/concurrently#readme) 

npm scriptsのコマンドを同時に実行する
ここでは、watch系のコマンドを同時に実行している
npm-run-allの並列実行では実現できなかったのでこちらを使用


### まとめ

とありえずやりたかったことはできました。

あんまりnpm scriptsの流儀はわかってません。
つっこみ歓迎。
もっとこんな方法があるよとかでも。
フォークして使ってもらうもよし。