coverPiccoverPic

踩坑:Nest 无法加载 ESModule


theme: channing-cyan

问题

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

ts
  1. import { fileTypeFromFile } from 'file-type'

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

cmd
  1. module.exports = require("file-type");
  2. ^
  3. Error [ERR_REQUIRE_ESM]: require() of ES Module xxx\node_modules\file-type\index.js from yyy not supported.
  4. 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 这个库中导出的函数:

ts
  1. // ...
  2. async function fileTypeFromStream(stream) {
  3. return new FileTypeParser().fromStream(stream);
  4. }
  5. async function fileTypeFromBuffer(input) {
  6. return new FileTypeParser().fromBuffer(input);
  7. }
  8. async function fileTypeFromBlob(blob) {
  9. return new FileTypeParser().fromBlob(blob);
  10. }
  11. // ...

修改 Webpack 配置

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

json
  1. {
  2. "$schema": "https://json.schemastore.org/nest-cli",
  3. "collection": "@nestjs/schematics",
  4. "sourceRoot": "src",
  5. "compilerOptions": {
  6. "deleteOutDir": true,
  7. "webpack": true,
  8. "webpackConfigPath": "./webpack.config.js"
  9. }
  10. }

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

ts
  1. const fs = require('fs')
  2. const path = require('path')
  3. const nodeExternals = require('webpack-node-externals');
  4. const appDirectory = fs.realpathSync(process.cwd());
  5. module.exports = function (options, webpack) {
  6. console.log('My Webpack Config ...');
  7. return {
  8. ...options,
  9. resolve: {
  10. extensions: [".ts", ".js"],
  11. alias: {
  12. 'src': path.resolve(appDirectory, 'src')
  13. }
  14. },
  15. externals: [
  16. nodeExternals({
  17. allowlist: ['file-type', /^strtok3/, 'peek-readable', 'token-types']
  18. })
  19. ],
  20. }
  21. }

重新运行就跑起来了。

结语

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

有什么不足请批评指正… 大家的阅读是我发帖的动力。
本文首发于我的博客:deer.shika-blog.xyz/

0 条评论未登录用户
Ctrl or + Enter 评论
© 2023-2025 LittleRangiferTarandus, All rights reserved.
🌸 Run