掘金 后端 ( ) • 2024-03-31 10:26

theme: channing-cyan

问题

💢💢在 Nest 项目中,我使用了 file-type 来识别文件类型。就像这样子:

import { fileTypeFromFile } from 'file-type'

这时候控制台就出现了报错:

module.exports = require("file-type");
                 ^
Error [ERR_REQUIRE_ESM]: require() of ES Module xxx\node_modules\file-type\index.js from yyy not supported.
Instead change the require of index.js in yyy to a dynamic import() which is available in all CommonJS modules.

Nest 使用的是 CommonJs 模块,加载 ESModule 的模块时出现了错误。这里是说我们使用了require导入 ESModule,但是我们用的 file-type 明明是 ESModule 模块。

解决方法

出现这个问题的原因是 Nest-CLI 内置的 Webpack 把所有import语句都编译成 CommonJs 的形式了。file-type 这个包是 ESModule 形式的,解决方法自然是自定义 Webpack 配置,阻止它把 ESModule 的模块打包成 commonjs 的形式。

这里使用 webpack-node-externals 这个 Webpack 第三方包(??反正它不是 loader,也不是 plugin)。它主要用于排除项目中的内置模块和 node_modules 中的第三方模块,会为被排除的模块创建一个外部函数。例如,我们排除了 file-type 这个库,在打包完成后的 ./dist/main.js 中,在最外层的代码可以找到 file-type 这个库中导出的函数:

// ...
async function fileTypeFromStream(stream) {
	return new FileTypeParser().fromStream(stream);
}

async function fileTypeFromBuffer(input) {
	return new FileTypeParser().fromBuffer(input);
}

async function fileTypeFromBlob(blob) {
	return new FileTypeParser().fromBlob(blob);
}
// ...

修改 Webpack 配置

找到项目根目录的 nest-cli.json,compilerOptions加入webpackwebpackConfigPath的属性:

{
  "$schema": "https://json.schemastore.org/nest-cli",
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "deleteOutDir": true,
    "webpack": true,
    "webpackConfigPath": "./webpack.config.js"
  }
}

./webpack.config.js 就是自定义 Webpack 配置的路径,在项目根目录新建 webpack.config.js。使用 webpack-node-externals 来忽略转换指定的模块或者文件,把涉及到的包都扔进去。

const fs = require('fs')
const path = require('path')
const nodeExternals = require('webpack-node-externals');
const appDirectory = fs.realpathSync(process.cwd());
module.exports = function (options, webpack) {
  console.log('My Webpack Config ...');
  return {
    ...options,
    resolve: {
      extensions: [".ts", ".js"],
      alias: {
        'src': path.resolve(appDirectory, 'src')
      }
    },
    externals: [
      nodeExternals({
        allowlist: ['file-type', /^strtok3/, 'peek-readable', 'token-types']
      })
    ],
  }
}

重新运行就跑起来了。

结语

初次用 Nest 做了个练习性的小项目,一开始对 Nest 中 webpack 的配置又不太了解,遇到问题还是花了不少时间的。这也是熟悉了一下 Node.js 的打包。

有什么不足请批评指正...... 大家的阅读是我发帖的动力。
本文首发于我的博客:deerblog.gu-nami.com/