JavaScript
vue
webpack
loader

webpackのローダー作ってみたら楽だった

More than 1 year has passed since last update.

Vueのuiフレームちっくなのを作ってて、コンポーネントの名前空間や、sassと共有管理しているcssプレフィックを動的に.vue(&js)ファイルに書きたかった。
また、コンポーネントごとにrender関数にパースされる前の生のテンプレート構文をドキュメントに落としたくて、できればこういうのも含めて事前処理を自前できる仕組み作りたいなと思ってた、
で、vue-loaderの前に一段自作のローダーおいたら行けるんじゃねかと思ったらいけた。

const loaderUtils = require('loader-utils');



module.exports = function(source, map) {
  this.cacheable();

  const options = loaderUtils.getOptions(this);

  source = source
    .replace(/vn@/g, options.vue.nameSpace)
    .replace(/vc@/g, options.css.prefix);

  this.callback(null, source, map);
};

ただ単に「vn@」があればVue用の名前空間、「vc@」があればcssプレフィックスに置換するだけ。(先読み否定的な安全対策はこのあとやる予定)
このローダをwebpack.config.jsに挟む。

webpack.config.js
  resolveLoader: {
    modules: ['node_modules', 'lib'],
  },

中略

      {
        test: /\.(vue|js)$/,
        enforce: 'pre',
        loader: 'hoge-loader',
        exclude: /node_modules/,
        options: publicSettings,
      },

      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig,
      },

すると、以下のようなvue(or js)ファイルがかける。

<template>
  <div>
    <main class="vc@container">
      <h1>dd-skelton</h1>
      <p class="vc@text-caption">
        Webコンテンツ制作の際の雛形です。基本的なエレメントのcssマークアップと、vueコンポーネントを実装済みです。
      </p>

      <div>
        <h2>Flat</h2>
        <vn@-btn
          v-for="type in CONTEXT_TYPES"
          :key="type"
          v-bind="{[type]: true}"
          flat
        >{{type}}</vn@-btn>

全ての「vn@」と「vc@」は定義済みの文字列に置換される。

webpackは結局今のところ捨てられなそうなので
こういう風に楽にローダ挟める仕組みを用意してくれてるのが感動した。
その気になれば自前でaltjs的なのも作れるよーな。。。絶対やらんけど

※追記(2017/10/6)

ただこの形でじゃんじゃかプロジェクト固めちゃうと、自前ローダーありきなソースになっちゃうので、
プレーンなJSとして利用できなくなるデメリットは多いにあり。
、、からその時が来た時のためにリファクタしやすい様置換文字列を「置換しやすい文字列」にしとく方が良いと思う。
あと、めちゃくちゃローカルルールになっちゃうのでプロジェクトメンバが増えると導入コストがかかると思う。
(その辺が怖くてTypeScriptやCoffee Script使ってないとこもあるので)