emahiro/b.log

日々の勉強の記録とか育児の記録とか。

いまさらだけどyarn + webpackを試す

仕事の中でjsの開発環境を構築する機会があったので、自前でes6をコンパイルする環境をととえてみた備忘録。
jsは動きが早くて色んなツールが出て来るなか、一定出尽くして落ち着いてきそうな感じをここ最近感じていたので、ようやく少しずつキャッチアップしていこうと思いました。

サマリ

  • yarn + webpack導入
  • es6を動かす
  • es6で書いたコードを動かす

どうしてyarnにしてのか

yarnとは?
facebookが開発したnext npm的なポジションのpackageマネージャー

去年10月にローンチして、徐々に使用事例が多くなってきたので自前でjsのモダンな開発環境を作るにあたって採用してみようと思ったから。

yarnのいいところ

https://qiita.com/0829/items/ec5271c06f8ff0633dd3 あたりを参考にした。

npmが生成した package.json を読み込める用に作られているので、npmとの互換性が保たれているので、正直どちらを使ってもいいと思われるが、npmより高速に動作し、依存関係やバージョン等も厳格に管理することができるため、npmでもできるが、yarnを積極的に使わない理由も弱い。

といった感想を持っている。

導入手順

yarn init

$ mkdir MyProject
$ cd MyProject
$ yarn init
yarn init
yarn init v1.1.0
...
success Saved package.json

対話式でプロジェクトの概要をセットアップしていく。
完了したらpackage.jsonができる

babelの設定

babelを使う場合は、 .babelrc が必要なものかと思ってましたが、webpackの場合は webpack.config.jsコンパイルの定義を書けます。

babelと一緒にes2015(es6)の構文対応できるように、 babel-preset-env をインストールします。

$ yarn add -D babel-loader babel-core babel-preset-env

当初 babel-preset-es2015 を入れてましたが、yarn add している最中に warning babel-preset-es2015@6.24.1: 🙌 Thanks for using Babel: we recommend using babel-preset-env now: please read babeljs.io/env to update! というwarnを受けたので、 babel-preset-env を入れました。

refs: https://babeljs.io/env/
github: https://github.com/babel/babel-preset-env

webpack.config.jsの設定

コンパイル元のファイルはentryに書いて、1つに固めたファイルの出力先がoutput。

というわけで出来上がった webpack.config.js はこちら

const src = __dirname + "/src";
const dist = __dirname + "/dist"

var webpack = require('webpack');

module.exports = {
  context: src,
  entry: "./index.js",
  output: {
    path: dist,
    filename: "index.min.js"
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude:/node_modules/,
        loader: "babel-loader",
        query: {
          presets:[
            ["env"]
          ]
        }
      }
    ]
  }
};

es6の導入

ディレクトリ構成は以下

MyProject
  src
    index.js
  dist
    index.min.js

このindex.jsにes6の構文で書いて、コンパイル後index.min.jsがちゃんと読み込まれるかを確認する

おまけ

難読化(UglifyJS)

コンパイルしたファイルを難読化する。
webpackには標準でUglifyJSがあるので、これを plugins に追加したが、defaultの難読化プラグインコンパイル時にエラーが発生した

$ yarn run build
yarn run v1.1.0
$ yarn run --config webpack
Hash: 2689b764da6353bc4101
Version: webpack 3.6.0
Time: 341ms
       Asset     Size  Chunks             Chunk Names
index.min.js  3.11 kB       0  [emitted]  main
   [0] ./index.js 371 bytes {0} [built]
   [1] ./person.js 162 bytes {0} [built]

ERROR in index.min.js from UglifyJs
Unexpected token: name (Friend) [index.min.js:79,6]
error Command failed with exit code 2.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

標準のuglify-jsが動かなかったので、uglifyjs-webpack-pluginを使う
refs: https://www.npmjs.com/package/uglifyjs-webpack-plugin

$ yarn add -D uglifyjs-webpack-plugin
const src = __dirname + "/src";
const dist = __dirname + "/dist"

var webpack = require('webpack');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin') //追加

module.exports = {
  context: src,
  entry: "./index.js",
  output: {
    path: dist,
    filename: "index.min.js"
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude:/node_modules/,
        loader: "babel-loader",
        query: {
          presets:[
            ["env", {
              "targets": {
                "node": "current"
              }
            }]
          ]
        }
      }
    ]
  },
  plugins: [
    new UglifyJSPlugin() //追加
  ]
};

webpackを動かす

yarn run build
yarn run v1.1.0
$ yarn run --config webpack
Hash: 2689b764da6353bc4101
Version: webpack 3.6.0
Time: 381ms
       Asset       Size  Chunks             Chunk Names
index.min.js  786 bytes       0  [emitted]  main
   [0] ./index.js 371 bytes {0} [built]
   [1] ./person.js 162 bytes {0} [built]
✨  Done in 1.37s.

$ cat dist/index.min.js
!function(e){function t(n){if(r[n])return r[n].exports;var u=r[n]={i:n,l:!1,exports:{}};return e[n].call(u.exports,u,u.exports,t),u.l=!0,u.exports}var r={};t.m=e,t.c=r,t.d=function(e,r,n){t.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:n})},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=0)}([function(e,t,r){"use strict";var n=function(e){return e&&e.__esModule?e:{default:e}}(r(1));class u extends n.default{constructor(e){super(name)}callName(){alert(this.name)}}new u("Taro").callName()},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});class n{constructor(e){this.n=e}}t.default=n}]);⏎

ちゃんと難読化されている。

動かしてみる

webpackにはlocalにサーバーを立てるライブラリ webpack-dev-server があるのでこちらを使う

$ yarn add -D webpack-dev-server
$ yarn run webpack-dev-server //これで動作させることができる。

上記でも問題ないがscriptを作成した

"scritps": {
  "start": "yarn run webpack-dev-server"
  "build":...
}

devserverはデフォルトは8080ポートで動作するが、手元のgoとパッティングするので3000番portに変更。
以下を webpack.config.json に追加する

const src = __dirname + "/src";
const dist = __dirname + "/dist"

var webpack = require('webpack');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')

module.exports = {
  context: src,
  entry: "./index.js",
  output: {
    path: dist,
    filename: "index.min.js"
  },
  devServer: {
    contentBase: dist,
    port: 3000
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude:/node_modules/,
        loader: "babel-loader",
        query: {
          presets:[
            ["env", {
              "targets": {
                "node": "current"
              }
            }]
          ]
        }
      },
      // 以下でhtmlの読み込みも追加する
      {
        test: /\.html$/, 
        loader: "file?name=[path][name].[ext]"
      }
    ]
  },
  plugins: [
    new UglifyJSPlugin()
  ]
};

サーバーを起動させる

yarn run start
yarn run v1.1.0
$ yarn run webpack-dev-server
Project is running at http://localhost:3000/
webpack output is served from /
Content not from webpack is served from ~/emahiro/es6_sample/dist
Hash: 093cadee3f8742a9e298
Version: webpack 3.6.0
Time: 2247ms
       Asset    Size  Chunks             Chunk Names
...
webpack: Compiled successfully.

注目すべきは以下

webpack output is served from /
Content not from webpack is served from ~/emahiro/es6_sample/dist

サーブされているのは / だけど、実際にはdistがwebから見たときのcontentのrootになる

dist
  index.min.js

というディレクトリ構造をしている場合、htmlからjsを呼び出すときは ./index.min.js と直書きする。

サーバーが起動した状態で localhost:3000 にアクセスしたら alert が発火するはず。
発火したら正常にes6がコンパイルされて動作していることになる。

所感

今までjsの潮流が早すぎて、正直足突っ込んだら抜けられなくなりそうだったので、避けてきた分野でしたが、webpackを使うことでjsド素人でも簡単にes6をプロジェクトに取り入れることが出来ました。

色々試せそうですが、次はtypescript入れてコンパイルしてみようと思います。