繁体   English   中英

使用 webpack 将 nestjs 应用程序捆绑到 1 个包含所有依赖项的文件中

[英]Bundle nestjs app into 1 file with all dependencies using webpack

我正在尝试创建 1 个可以为运行我的 nestjs 应用程序提供的文件。 我设法从构建过程中创建了 1 个文件,但是当在不同位置的不同机器/我的机器上运行它时,当我的项目是我得到以下 output:

node main.js
node:internal/modules/cjs/loader:936
  throw err;
  ^

Error: Cannot find module '@nestjs/core'
Require stack:
- C:\Users\xxx\Desktop\Temp\main.js
[90m    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)[39m
[90m    at Function.Module._load (node:internal/modules/cjs/loader:778:27)[39m
[90m    at Module.require (node:internal/modules/cjs/loader:1005:19)[39m
[90m    at require (node:internal/modules/cjs/helpers:102:18)[39m
    at Object.__decorate (C:\Users\xxx\Desktop\Temp\main.js:8:18)
    at __webpack_require__ (C:\Users\xxx\Desktop\Temp\main.js:3635:42)
    at C:\Users\xxx\Desktop\Temp\main.js:3648:16
    at C:\Users\xxx\Desktop\Temp\main.js:3656:3
    at Object.<anonymous> (C:\Users\xxx\Desktop\Temp\main.js:3658:12)
[90m    at Module._compile (node:internal/modules/cjs/loader:1105:14)[39m {
  code: [32m'MODULE_NOT_FOUND'[39m,
  requireStack: [ [32m'C:\\Users\\xxx\\Desktop\\Temp\\main.js'[39m ]
-------

\Desktop\Temp\main.js:3658:12)
[90m    at Module._compile (node:internal/modules/cjs/loader:1105:14)[39m {
  code: [32m'MODULE_NOT_FOUND'[39m,
  requireStack: [ [32m'C:\\Users\\xxx\\Desktop\\Temp\\main.js'[39m ]

webpack.config.js( 取自这篇文章):

const path = require('path');
const webpack = require('webpack');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

const WebPackIgnorePlugin = {
  checkResource: function (resource) {
    const lazyImports = [
      '@nestjs/microservices',
      '@nestjs/microservices/microservices-module',
      'cache-manager',
      'class-transformer',
      'class-validator',
      'fastify-static',
    ];

    if (!lazyImports.includes(resource)) return false;

    try {
      require.resolve(resource);
    } catch (err) {
      return true;
    }

    return false;
  },
};

module.exports = {
  mode: 'production',
  target: 'node',
  entry: {
    server: './src/main.ts',
  },
  devtool: 'source-map',
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
    ],
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
  },
  node: {
    __dirname: false,
  },
  plugins: [
    new CleanWebpackPlugin(),
    new webpack.IgnorePlugin(WebPackIgnorePlugin),
  ],
  optimization: {
    minimize: false,
  },
  performance: {
    maxEntrypointSize: 1000000000,
    maxAssetSize: 1000000000,
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'prod'),
  },
};

Package.json:

 "scripts": {
    "prebuild": "rimraf dist",
    "build": "nest build --webpack",
    "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
    "start": "nest start --entryFile ./my-app/src/main.js",
    "start:dev": "nest start --entryFile ./my-app/src/main.js --watch",
    "start:debug": "nest start --debug --watch",
    "start:prod": "node dist/main",
    "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:cov": "jest --coverage",
    "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
    "test:e2e": "jest --config ./test/jest-e2e.json"
  },
  "dependencies": {
    "@nestjs/common": "^8.0.0",
    "@nestjs/core": "^8.0.0",
    "@nestjs/platform-express": "^8.0.0",
    "@stablelib/aes-kw": "^1.0.1",
    "bcryptjs": "^2.4.3",
    "core-js": "^3.18.1",
    "csv-parser": "^3.0.0",
    "ec-key": "^0.0.4",
    "express": "^4.17.3",
    "fast-xml-parser": "^3.20.3",
    "futoin-hkdf": "^1.4.2",
    "net-snmp": "^3.5.5",
    "object.pick": "^1.3.0",
    "path": "^0.12.7",
    "pkcs11js": "^1.3.0",
    "reflect-metadata": "^0.1.13",
    "rimraf": "^3.0.2",
    "rxjs": "^7.2.0",
    "serialport": "^10.4.0",
    "sqlite3": "^5.0.2",
    "ssh2": "^1.11.0",
    "sshpk": "^1.17.0",
    "strftime": "^0.10.1",
    "tftp": "^0.1.2",
    "tsconfig-paths-webpack-plugin": "^4.0.0",
    "webpack-cli": "^4.10.0",
    "winston": "^3.3.3",
    "winston-transport": "^4.4.0"
  },
  "devDependencies": {
    "@nestjs/cli": "^8.0.0",
    "@nestjs/schematics": "^8.0.0",
    "@nestjs/testing": "^8.0.0",
    "@types/express": "^4.17.13",
    "@types/jest": "27.5.0",
    "@types/node": "^16.0.0",
    "@types/supertest": "^2.0.11",
    "@typescript-eslint/eslint-plugin": "^5.0.0",
    "@typescript-eslint/parser": "^5.0.0",
    "eslint": "^8.0.1",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-prettier": "^4.0.0",
    "jest": "28.0.3",
    "prettier": "^2.3.2",
    "source-map-support": "^0.5.20",
    "supertest": "^6.1.3",
    "ts-jest": "28.0.1",
    "ts-loader": "^9.2.3",
    "ts-node": "^10.0.0",
    "tsconfig-paths": "4.0.0",
    "typescript": "^4.3.5",
    "webpack": "^5.74.0",
    "webpack-merge": "^5.8.0"
  },
  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      "ts"
    ],
    "rootDir": "src",
    "testRegex": ".*\\.spec\\.ts$",
    "transform": {
      "^.+\\.(t|j)s$": "ts-jest"
    },
    "collectCoverageFrom": [
      "**/*.(t|j)s"
    ],
    "coverageDirectory": "../coverage",
    "testEnvironment": "node"
  }

构建 output:

> npm run build

> my-app@0.0.1 prebuild
> rimraf dist


> my-app@0.0.1 build
> nest build --webpack

webpack 5.73.0 compiled successfully in 10253 ms

output 产生1个文件: main.js

在 webpack 配置文件中,您有所有 node_modules 的exclude规则:使用webpack-node-externals尝试这个简单的配置并确保清理 node_modules 并重新安装所有

const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals');
const { TsconfigPathsPlugin } = require('tsconfig-paths-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const { RunScriptWebpackPlugin } = require('run-script-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const path = require('path');

const tsConfigFile = 'tsconfig.build.json';

const lazyImports = [
  '@nestjs/microservices',
  'cache-manager',
  'class-validator',
  'class-transformer',
];

const config = {
  entry: {
    server: `./src/main.ts`,
    'app-init': './scripts/app-init.ts',
    'prisma-migrations': './scripts/prisma-migrations.ts',
  },
  output: {
    filename: `[name].js`,
    path: path.join(__dirname, 'dist'),
    devtoolModuleFilenameTemplate: `${path.sep}[absolute-resource-path][loaders]`,
  },
  cache: {
    type: 'filesystem',
    cacheDirectory: path.resolve(__dirname, '.build_cache'),
  },
  devtool: false,
  target: 'node',
  mode: 'none',
  optimization: {
    nodeEnv: false,
  },
  node: {
    __filename: false,
    __dirname: false,
  },
  externals: [nodeExternals()],
  module: {
    rules: [
      {
        test: /.ts?$/,
        include: [
          path.resolve(__dirname, 'src'),
        ],
        use: [
          {
            loader: 'ts-loader',
            options: {
              transpileOnly: true,
              configFile: tsConfigFile,
            },
          },
        ],
        exclude: /node_modules/,
      },
    ],
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
    plugins: [
      new TsconfigPathsPlugin({
        configFile: tsConfigFile,
      }),
    ],
  },
  plugins: [
    new webpack.ProgressPlugin(),
    new webpack.IgnorePlugin({
      checkResource(resource) {
        if (!lazyImports.includes(resource)) {
          return false;
        }
        try {
          require.resolve(resource, {
            paths: [process.cwd()],
          });
        } catch (err) {
          return true;
        }
        return false;
      },
    }),
    new CleanWebpackPlugin(),
    new ForkTsCheckerWebpackPlugin({
      typescript: {
        configFile: tsConfigFile,
      },
    }),
  ],
};

module.exports = (
  env = { debug: false },
  argv = { mode: 'none', watch: false },
) => {
  config.mode = argv.mode;

  if (argv.mode === 'development') {
    config.watch = argv.watch;
    config.cache.name = env.debug ? 'development_debug' : 'development';
    config.devtool = env.debug ? 'eval-source-map' : undefined;

    // If running in watch mode
    if (config.watch) {
      config.cache.name = env.debug
        ? 'development_debug_hmr'
        : 'development_hmr';
      config.entry = {
        ...config.entry,
        server: [
          'webpack/hot/poll?100',
          'webpack/hot/signal',
          config.entry.server,
        ],
      };
      config.externals = [
        nodeExternals({
          allowlist: ['webpack/hot/poll?100', 'webpack/hot/signal'],
        }),
      ];
      config.plugins = [
        ...config.plugins,
        new webpack.WatchIgnorePlugin({ paths: [/\.js$/, /\.d\.ts$/] }),
        new webpack.HotModuleReplacementPlugin(),
        new RunScriptWebpackPlugin({
          name: 'server.js',
          nodeArgs: env.debug ? ['--inspect'] : undefined, // Allow debugging
          signal: true, // Signal to send for HMR (defaults to `false`, uses 'SIGUSR2' if `true`)
          keyboard: true, // Allow typing 'rs' to restart the server. default: only if NODE_ENV is 'development'
          // args: ['scriptArgument1', 'scriptArgument2'], // pass args to script
        }),
      ];
    }
  }

  if (argv.mode === 'production') {
    config.devtool = 'source-map';
    config.cache.name = 'production';
    config.optimization.minimize = true;
    config.optimization.minimizer = [
      new TerserPlugin({
        terserOptions: {
          keep_classnames: true,
          keep_fnames: true,
        },
      }),
    ];
  }

  return config;
};

加上一些与 nextjs 相关的 tsconfig 编辑:

{
  "compilerOptions": {
    "module": "esnext",
    "moduleResolution": "node",
    ...
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM