🔨

webpack/特定ファイルのビルドで別Loaderを使用する

2022/01/17に公開

動機

TypeScript + AWS Lambda のバックエンドをデプロイする際に、webpackのビルド時間を早くできないかと思い、 ts-loader から esbuild-loader へ移行を試みていました。

しかしながら、RDS(MySQL)のORMに TypeORM を使用していたため、 esbuild-loader がemitDecoratorMetadata には対応しておらず、ビルドエラーを吐いたのでDecoratorを含むファイルはts-loaderで、含まないファイルはesbuild-loaderでビルドできないか調査しました。

解決法

リンクにあるgithub discussionの記事通りではあるのですが、webpack.config.js 内の test propertyでビルド対象のファイルのパス(String)を取得できるので、あとはファイルのパスがルールに一致すれば esbuild-loader を使用するよう webpackの oneOf を使用し、正規表現でよしなに。

function hasDecorator(fileContent, offset = 0) {
  const atPosition = fileContent.indexOf('@', offset)
  if (atPosition === -1) {
    return false
  }
  if (atPosition === 1) {
    return true
  }
  if (["'", '"'].includes(fileContent.substr(atPosition - 1, 1))) {
    return hasDecorator(fileContent, atPosition + 1)
  }
  return true
}

modules.exports = {
  module: {
    rules: [
      {
        test: /\.(ts)$/,
        oneOf: [
          {
	    test: (filePath) => {
	      if (!filePath) {
	        return false
	      }
	      try {
	        const fileContent = fs.readFileSync(filePath).toString()
	        return !hasDecorator(fileContent)
	      } catch (e) {
	         console.error(`uncaught error`)
	        return false
	      }
	    },
	    use: [
	      loader: 'esbuild-loader',
	      options: {
	        loader: 'ts',
	        target: 'es2017',
	      },
	    ],
	  },
	  {
	    use: [
	      loader: 'ts-loader',
	      options: {
	        transpileOnly: true,
	      },
	    ],
	  },
	},
      ],
    ],
  },
}

リンク

https://github.com/privatenumber/esbuild-loader/discussions/117

Discussion