我最近创建了一个 nx 工作区并添加到 Express 应用程序中。正如您所期望的,这是开箱即用的。但是,一旦我添加对 ESM 库(例如 nanoid v4+)的依赖项,我就无法启动服务器,并且收到以下错误消息。
Error [ERR_REQUIRE_ESM]: require() of ES Module /workspace/node_modules/nanoid/index.js not supported
配置 NX 工作区和 Express 应用程序以便能够导入 ESM 库和本地工作区库并成功测试/构建/提供应用程序的正确方法是什么?
npx nx run my-express-api:testnpx nx run my-express-api:buildnpx nx run my-express-api:serve尝试1
这是开箱即用的尝试
错误:
Error [ERR_REQUIRE_ESM]: require() of ES Module /workspace/node_modules/nanoid/index.js not supported.
Instead change the require of index.js in null to a dynamic import() which is available in all CommonJS modules.
at Module._load (/workspace/node_modules/@nx/js/src/executors/node/node-with-require-overrides.js:18:31)
at Array.__webpack_modules__ (/workspace/dist/apps/my-express-api/main.js:26:18)
at __webpack_require__ (/workspace/dist/apps/my-express-api/main.js:49:41)
at /workspace/dist/apps/my-express-api/main.js:69:18
at /workspace/dist/apps/my-express-api/main.js:81:3
at Object.<anonymous> (/workspace/dist/apps/my-express-api/main.js:83:12)
at Module._load (/workspace/node_modules/@nx/js/src/executors/node/node-with-require-overrides.js:10:31)
Run Code Online (Sandbox Code Playgroud)
配置:
快速应用程序tsconfig.app.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["node", "express"]
},
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
"include": ["src/**/*.ts"]
}
Run Code Online (Sandbox Code Playgroud)
快速应用程序webpack.config.js
const { NxWebpackPlugin } = require('@nx/webpack');
const { join } = require('path');
module.exports = {
output: {
path: join(__dirname, '../../dist/apps/my-express-api'),
},
plugins: [
new NxWebpackPlugin({
target: 'node',
compiler: 'tsc',
main: './src/main.ts',
tsConfig: './tsconfig.app.json',
assets: ['./src/assets'],
optimization: false,
outputHashing: 'none',
}),
],
};
Run Code Online (Sandbox Code Playgroud)
快递应用程序project.json
{
"name": "my-express-api",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/my-express-api/src",
"projectType": "application",
"targets": {
"serve": {
"executor": "@nx/js:node",
"defaultConfiguration": "development",
"options": {
"buildTarget": "my-express-api:build"
},
"configurations": {
"development": {
"buildTarget": "my-express-api:build:development"
},
"production": {
"buildTarget": "my-express-api:build:production"
}
}
}
},
"tags": []
}
Run Code Online (Sandbox Code Playgroud)
根工作区package.json
{
"name": "nx-template",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"start": "nx serve",
"build": "nx build",
"test": "nx test"
},
"private": true,
"dependencies": {
"@emotion/react": "11.11.1",
"@emotion/styled": "11.11.0",
"axios": "^1.6.0",
"express": "^4.18.1",
"lodash-es": "^4.17.21",
"nanoid": "^5.0.5",
"react": "18.2.0",
"react-dom": "18.2.0",
"tslib": "^2.3.0"
},
"devDependencies": {
"@emotion/babel-plugin": "11.11.0",
"@nx/eslint": "18.0.4",
"@nx/eslint-plugin": "18.0.4",
"@nx/express": "18.0.4",
...
}
}
Run Code Online (Sandbox Code Playgroud)
尝试2
修改 tsconfig/webpack 设置。
这些修改并不理想,但这确实允许我导入 ESM 库。但是,我现在无法导入本地工作区库。
错误:
ERROR in ./apps/my-express-api/src/main.ts 9:0-35
Module not found: Error: Can't resolve 'test-lib' in '/workspace/apps/my-express-api/src'
resolve 'test-lib' in '/workspace/apps/my-express-api/src'
Parsed request is a module
using description file: /workspace/apps/my-express-api/package.json (relative path: ./src)
resolve as module
/workspace/apps/my-express-api/src/node_modules doesn't exist or is not a directory
/workspace/apps/my-express-api/node_modules doesn't exist or is not a directory
/workspace/apps/node_modules doesn't exist or is not a directory
looking for modules in /workspace/node_modules
single file module
using description file: /workspace/package.json (relative path: ./node_modules/test-lib)
no extension
/workspace/node_modules/test-lib doesn't exist
.js
/workspace/node_modules/test-lib.js doesn't exist
.mjs
/workspace/node_modules/test-lib.mjs doesn't exist
.ts
/workspace/node_modules/test-lib.ts doesn't exist
.mts
/workspace/node_modules/test-lib.mts doesn't exist
/workspace/node_modules/test-lib doesn't exist
/node_modules doesn't exist or is not a directory
Run Code Online (Sandbox Code Playgroud)
配置:
项目.json
...
"build": {
"executor": "@nx/webpack:webpack",
"dependsOn": ["lint"],
"outputs": ["{options.outputPath}"],
"options": {
"target": "node",
"compiler": "tsc",
"outputPath": "dist/apps/my-express-api",
"main": "apps/my-express-api/src/main.ts",
"tsConfig": "apps/my-express-api/tsconfig.app.json",
"assets": ["apps/my-express-api/src/assets"],
"isolatedConfig": true,
"webpackConfig": "apps/my-express-api/webpack.config.cjs",
}
},
...
Run Code Online (Sandbox Code Playgroud)
笑话.config.json
/* eslint-disable */
export default {
displayName: 'new-app-server',
preset: '../../jest.preset.js',
testEnvironment: 'node',
transform: {
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../../coverage/apps/my-express-api',
};
Run Code Online (Sandbox Code Playgroud)
包.json
{
"name": "my-express-api",
"version": "0.0.1",
"type": "commonjs"
}
Run Code Online (Sandbox Code Playgroud)
tsconfig.json
{
"extends": "../../tsconfig.base.json",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.spec.json"
}
],
"compilerOptions": {
"module": "ES2022",
"moduleResolution": "bundler",
"esModuleInterop": true
}
}
Run Code Online (Sandbox Code Playgroud)
tsconfig.app.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "ESNext",
"strict": true,
"types": ["node", "express"]
},
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
"include": ["src/**/*.ts"]
}
Run Code Online (Sandbox Code Playgroud)
webpack.config.cjs
const path = require('path');
const nodeExternals = require('webpack-node-externals');
module.exports = {
mode: 'development', // or 'production' for production mode
entry: './apps/my-express-api/src/main.ts', // Entry point of your Express application
output: {
path: path.resolve(__dirname, '../../dist/apps/my-express-api'),
filename: 'main.mjs',
module: true,
libraryTarget: 'module',
chunkFormat: 'module',
chunkFilename: 'main.mjs',
library: {
type: 'module',
},
environment: {
module: true,
},
},
node: {
__dirname: 'node-module',
},
resolve: {
extensions: ['.js', '.mjs', '.ts', '.mts'], // Support both .js and .mjs extensions for ESM
extensionAlias: {
'.js': ['.ts', '.js'],
'.mjs': ['.mts', '.mjs'],
'.cjs': ['.cts', '.cjs'],
},
},
target: 'node', // Important for server-side applications
externals: [nodeExternals({ importType: 'module' })], // Exclude node_modules from the bundle
externalsPresets: {
node: true,
},
module: {
rules: [
// Add any necessary loaders or rules here
{ test: /\.([cm]?ts|tsx)$/, loader: 'ts-loader' },
],
},
experiments: {
outputModule: true,
},
plugins: [
// Add any necessary plugins here
],
};
Run Code Online (Sandbox Code Playgroud)
尝试3
使用@nx/esbuild:esbuild
我以为我已经用这个解决方案解决了这个问题。如果我导入 esm 库(例如 nanoid v4+),那么我将不再收到错误Error [ERR_REQUIRE_ESM],并且我能够构建/提供我的应用程序。
当我尝试导入工作区 js 库时出现问题
错误:
error TS2307: Cannot find module '@myorg/mylib' or its corresponding type declarations.
Run Code Online (Sandbox Code Playgroud)
配置:
项目.json
...
"build": {
"executor": "@nx/esbuild:esbuild",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/apps/my-express-api",
"main": "apps/my-express-api/src/main.ts",
"tsConfig": "apps/my-express-api/tsconfig.app.json",
"assets": [],
"generatePackageJson": true,
"format": ["esm"],
"platform": "node",
"bundle": true
}
},
...
Run Code Online (Sandbox Code Playgroud)
包.json
{
"name": "my-express-api",
"version": "0.0.1",
"type": "module"
}
Run Code Online (Sandbox Code Playgroud)
tsconfig.app.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
// "outDir": "../../../dist/out-tsc",
"outDir": "dist",
"lib": ["ES2021"],
"module": "NodeNext",
"target": "ES2021",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "NodeNext",
"sourceMap": true,
"declaration": true,
"declarationMap": true,
"baseUrl": ".",
"resolveJsonModule": true,
"types": ["node", "express"]
},
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
"include": ["src/**/*.ts"],
}
Run Code Online (Sandbox Code Playgroud)
tsconfig.base.json
...
"paths": {
"@myorg/mylib": ["libs/mylib/src/index.ts"],
}
...
Run Code Online (Sandbox Code Playgroud)
编辑
尝试以下选项:
确保您的 Express 应用程序可以处理 ESM 和 CommonJS 模块。由于 Express 传统上是基于 CommonJS 的框架,并且您要引入像 nanoid 这样的 ESM 模块,因此您需要一个能够容纳这两者的设置。
在 tsconfig 中为后端代码设置 "module": "CommonJS"。这可确保 TypeScript 编译为 CommonJS,这是 Node.js 和 Express 的默认设置。使用 "moduleResolution": "node" 来利用 Node.js 的解析算法,它可以处理 CommonJS 和 ESM。对于 ESM 包,请考虑 CommonJS 和 ESM 环境都支持的动态导入(import() 语法)。NX 配置:NX 应自动处理大部分 TypeScript 配置和路径映射。确保 tsconfig.base.json 中的路径已为工作区库正确设置。
对 ESM 包(如 nanoid)使用动态导入。例如:
const { nanoid } =等待导入('nanoid');
这种方法是异步的,但允许您在 CommonJS 上下文中使用 ESM 模块。
| 归档时间: |
|
| 查看次数: |
104 次 |
| 最近记录: |