Typescript 转译错误仅出现在生产服务器上

Typescript transpile errors appear only on production server

在为两台机器更新我的节点版本/依赖项的过程中,我注意到 在另一台机器上构建我的生产应用程序会输出错误,而在我的主机上构建生产环境则不会。

如果我将受影响的 devDependencies 移动到我的 package.json 中的 dependencies 数组,错误就会消失,但这更像是一种解决方法,我想知道为什么我会看到不同的行为。

据我了解,当 运行 npm install 投入生产时,它 不会 安装我的开发依赖项。 这很好,因为我在我的开发机器上测试过它,即使没有我的开发依赖,应用程序也能正常构建。

但是,在生产中,我遇到如下错误:

Cannot find module 'sinon' or its corresponding type declarations.

Could not find a declaration file for module 'cors'. '/home/ubuntu/brobot/source/node_modules/cors/lib/index.js' implicitly has an 'any' type. Try `npm i --save-dev @types/cors` if it exists or add a new declaration (.d.ts) file containing `declare module 'cors';

如果我将受影响的包移动到 dependencies 数组而不是 dev dependencies,它们就会消失,但为什么呢?为什么它在我的开发机器上没有我的开发依赖性的情况下构建良好?

这是我的配置:

package.json 缩短:

{
  "main": "dist/src/index.js",
  "type": "module",
  "scripts": {
    "build": "rimraf dist && tsc",
    "test": "mocha",
    "dev:old": "cross-env NODE_ENV=development concurrently \"tsc -w\" \"nodemon -q -r dotenv/config --es-module-specifier-resolution=node dist/src/index.js\"",
    "deploy": "pm2 deploy ecosystem.config.cjs production",
    "preserve": "npm run build",
  },
  "dependencies": {
    "@pkmn/randoms": "^0.5.11",
    "@pkmn/sim": "^0.5.11",
    "@twurple/api": "^5.0.18",
    "@twurple/auth": "^5.0.18",
    "@twurple/chat": "^5.0.18",
    "@twurple/eventsub": "^5.0.18",
    "@twurple/eventsub-ngrok": "^5.0.18",
    "@types/cookie-session": "^2.0.44",
    "@types/express": "^4.17.13",
    "@types/express-ws": "^3.0.1",
    "@types/mocha": "^9.1.0",
    "@types/node": "^17.0.23",
    "@types/passport": "^1.0.7",
    "@types/request": "^2.48.8",
    "axios": "^0.26.1",
    "cookie-session": "^2.0.0",
    "cors": "^2.8.5",
    "dotenv": "^16.0.0",
    "express": "^4.17.3",
    "express-ws": "^5.0.2",
    "helmet": "^5.0.2",
    "mocha": "^9.2.2",
    "moment-timezone": "^0.5.34",
    "mongoose": "^6.2.8",
    "passport": "^0.5.2",
    "passport-oauth": "^1.0.0",
    "request": "^2.88.2",
    "rimraf": "^3.0.2",
    "typescript": "^4.6.2",
    "winston": "^3.6.0",
    "ws": "^8.5.0"
  },
  "devDependencies": {
    "@types/chai": "^4.3.0",
    "@types/cors": "^2.8.12",
    "@types/sinon": "^10.0.11",
    "@types/ws": "^8.5.3",
    "@typescript-eslint/eslint-plugin": "^5.16.0",
    "@typescript-eslint/parser": "^5.16.0",
    "chai": "^4.3.6",
    "concurrently": "^7.0.0",
    "cross-env": "^7.0.3",
    "eslint": "^8.11.0",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-import": "^2.25.4",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-prettier": "^4.0.0",
    "eslint-plugin-promise": "^6.0.0",
    "lint-staged": "^12.3.7",
    "nodemon": "^2.0.15",
    "pm2": "^5.2.0",
    "prettier": "^2.6.0",
    "sinon": "^13.0.1",
    "ts-node": "^10.7.0"
  },
  "lint-staged": {
    "*.{js,ts}": [
      "eslint --cache --fix",
      "prettier --check"
    ]
  }
}

tsconfig.json:

{
  "compilerOptions": {
    "target": "ES6",                                /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
    "module": "ESNext",                             /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */     /* Generates a sourcemap for each corresponding '.d.ts' file. */
    "sourceMap": true,                              /* Generates corresponding '.map' file. */
    "outDir": "dist",                               /* Redirect output structure to the directory. */
    "strict": true,                                 /* Enable all strict type-checking options. */
    "moduleResolution": "node",                     /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    "esModuleInterop": true,                        /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    "skipLibCheck": true,                           /* Skip type checking of declaration files. */
    "forceConsistentCasingInFileNames": true        /* Disallow inconsistently-cased references to the same file. */
  }
}

PM2 ecosystem.config.cjs:

require('dotenv').config();

// Default configuration
module.exports = {
    apps: [...],
    deploy: {
        production: {
            user: process.env.AWS_USER,
            host: process.env.AWS_PUBLIC_IP,
            key: process.env.AWS_SSH_KEY,
            ref: 'origin/main',
            repo: '...',
            path: process.env.AWS_EC2_PATH,
            node_args: "--experimental-modules --es-module-specifier-resolution=node",
            env: { NODE_ENV: 'production', },
            'post-deploy':
                'npm install && npm run build && pm2 startOrRestart ecosystem.config.cjs --env production'
                             ^^^^^^^^^^^^^^^ this is where errors are thrown in production. `npm run build` works fine on development without dev dependencies installed.
        }
    }
};

我考虑过的事情:

我尝试过的其他事情:

我的 dev/prod 机器之间肯定有一些配置错误。虽然它们是 运行 相同版本的 node 和 Typescript。 据我所知,两台机器都没有使用全局安装的软件包。奇怪的是,这之前在我的生产机器上运行得很好,尽管我可能没有 运行 它正确地使用生产标志。即使我的 node_env 是“生产”,它也可能在我不注意的情况下安装了我的开发依赖项。

我 运行 在这里没有选择,非常感谢任何帮助。

sinon 是一个开发依赖项,因此它没有捆绑用于生产。如果您需要它用于生产,您可以将它添加到依赖项中,如果不需要,您可以删除对 sinon 的引用并重新捆绑,它应该会自行解决。

编辑 1:

The errors go away if I move the affected devDependencies to the dependencies array in my package.json

我最初忽略了这一点。是的,听起来您在生产代码中使用了这些库,但由于它们不在依赖项中,因此它们不包含在您的生产包中。它们在开发中工作,因为您将它们作为开发依赖项。