84
63

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Webpackでフォルダ内の全ファイルを一気にrequireする

Last updated at Posted at 2017-08-23

Webpackには、CommonJSのrequireよりも強力な、依存関係処理機能があります。

ふつうのrequireとWebpack

npmで入れたライブラリを指定する場合にしても、自分で作ったファイルを呼び出す場合にしても、ほとんどの状況でrequireすべきファイルはソースコードの時点で決まっているものです。

Webpackでは、リテラルでrequireを行った場合、コンパイル後にはrequireの引数が、モジュールの番号に置き換わっています。

動的なrequireとコンテキスト

ただ、CommonJS Modulesの仕様でも、requireが取る引数は一定の書式の「文字列」となっているだけで、もちろんリテラル限定なんてことはありません。任意の文字列を指定することができます。

このような場合、ソースコードの時点では何をrequireするか決まらないので、固定的にコンパイルすることはもちろん不可能です。Webpackでは、requireするモジュールが決まりきらないコードを発見すると、「requireコンテキスト」を生成します。

requireコンテキストは、ソースコードから判別できる接頭辞・接尾辞(フォルダ位置・拡張子など)からできるだけ絞り込んだ上で、候補になりうるすべてのモジュールを用意した上で、最終的にrequireを呼び出した文字列で実際にrequireするものを決定する、というような流れになっています。

コンテキストを自分で作る

上で述べた「requireコンテキスト」は、Webpackが自動で用意するだけではなく、require.contextを呼び出すことで、自分で作ることもできます。

const context = require.context(directory, useSubdirectories = false, regExp = /^\.\//)

引数の意味は次のようになっていますが、コンパイル時に解決しないといけないため、すべてリテラルである必要があります。

  • directory…どこのディレクトリの中身をrequireの対象とするか
  • useSubdirectories…対象のディレクトリ直下だけ拾うならfalse、以下の全ディレクトリを対象にするならtrue
  • regExp…対象になるファイルが満たすべき条件を書いた正規表現(/\.js$/のように、拡張子指定に使うと便利です)

コンテキストの操作

コンテキストを作っただけでは、requireは行われません。このcontextは、以下のようなものからなっています。

  • context(パス)…指定されたパスのモジュールをrequireする(もちろん、コンテキストになければ失敗)
  • context.resolve(パス)…指定されたパスをモジュール番号に変換する(もちろん、コンテキストになければ失敗)
  • context.keys()…コンテキストに含まれるパスの配列を返す
  • context.id…コンテキスト自体のモジュール番号

実用例

Riot.jsとWebpackを組み合わせる場合、riot/tag-loaderがあるので、これを使えば.tagファイルもrequireできますし、require('riot')で呼び出されるRiot本体に、requireした時点でタグとして登録されます。

Riotのタグをセットする側でriot.mount('*')のようにするのであれば、requireしたものを自分で保存しておく必要もない、ということになります。ということで、タグは「ただrequireしておくだけでいい」ということになります。

このような場合、以下のコードで一括requireできます。

function allRequire(context){
  context.keys().forEach(context);
}

allRequire(require.context('./path/to/tags/', true, /\.tag$/))

forEach(context)が直感的ではありませんが、context自体が「モジュールのパスを受け取ってrequireする関数」なので、forEachが投げてくる「1つ目が値」というパターンにぴったりなのです。

参照

84
63
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
84
63

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?