javascript - Enkelfilsbundle med NestJS + Typescript + Webpack + node_modules


Hur? Hur kan jag paketera ett NestJS-projekt inklusive node_module för en offlineapplikation?

webpack.config.js

const path = require('path');

module.exports = {
  entry: path.join(__dirname, 'dist/main.js'),
  target: 'node',
  output: {
    filename: 'compiled.js',
    path: __dirname,
  },
  resolve: {
    alias: {
      node_modules: path.join(__dirname, 'node_modules'),
    },
    extensions: ['.js'],
  },
};

package.json

{
  "name": "kai-brs",
  "version": "0.9.1",
  "author": "Sovgut Sergey",
  "private": true,
  "scripts": {
    "build:webpack": "rimraf dist && tsc -p tsconfig.build.json && webpack dist/main.js -o dist/main.bundle.js --mode=production",
    "build": "tsc -p tsconfig.build.json",
    "format": "prettier --write \"src/**/*.ts\"",
    "start": "ts-node -r tsconfig-paths/register src/main.ts",
    "start:dev": "nodemon",
    "start:debug": "nodemon --config nodemon-debug.json",
    "prestart:prod": "rimraf dist && npm run build",
    "start:prod": "node dist/main.js",
    "lint": "tslint -p tsconfig.json -c tslint.json",
    "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": "^6.0.0",
    "@nestjs/core": "^6.0.0",
    "@nestjs/graphql": "^6.0.5",
    "@nestjs/platform-express": "^6.0.0",
    "@nestjs/typeorm": "^6.0.0",
    "@types/dotenv": "^6.1.1",
    "apollo-server-express": "^2.4.8",
    "dotenv": "^7.0.0",
    "graphql": "^14.2.1",
    "graphql-tools": "^4.0.4",
    "joi": "^14.3.1",
    "mssql": "^5.0.5",
    "multer": "^1.4.1",
    "public-ip": "^3.0.0",
    "reflect-metadata": "^0.1.12",
    "request": "^2.88.0",
    "request-promise": "^4.2.4",
    "rimraf": "^2.6.2",
    "rxjs": "^6.3.3",
    "screenshot-desktop": "^1.7.0",
    "typeorm": "^0.2.16",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.3.0"
  },
  "devDependencies": {
    "@nestjs/testing": "^6.0.0",
    "@types/express": "^4.16.1",
    "@types/jest": "^23.3.13",
    "@types/joi": "^14.3.2",
    "@types/node": "^10.12.18",
    "@types/supertest": "^2.0.7",
    "jest": "^23.6.0",
    "nodemon": "^1.18.9",
    "prettier": "^1.15.3",
    "supertest": "^3.4.1",
    "ts-jest": "^23.10.5",
    "ts-loader": "^5.3.3",
    "ts-node": "^7.0.1",
    "tsconfig-paths": "^3.7.0",
    "tslint": "5.12.1",
    "typescript": "^3.2.4"
  },
  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      "ts"
    ],
    "rootDir": "src",
    "testRegex": ".spec.ts$",
    "transform": {
      "^.+\\.(t|j)s$": "ts-jest"
    },
    "coverageDirectory": "../coverage",
    "testEnvironment": "node"
  }
}

Nu har jag dessa fel :(

WARNING in ./node_modules/public-ip/node_modules/got/source/request-as-event-emitter.js 72:18-25
Critical dependency: require function is used in a way in which dependencies cannot be statically extracted
 @ ./node_modules/public-ip/node_modules/got/source/as-promise.js
 @ ./node_modules/public-ip/node_modules/got/source/create.js
 @ ./node_modules/public-ip/node_modules/got/source/index.js
 @ ./node_modules/public-ip/index.js
 @ ./dist/service/illumenator.service.js
 @ ./dist/service/illumenator.module.js
 @ ./dist/service.module.js
 @ ./dist/main.js

WARNING in ./node_modules/typeorm/platform/PlatformTools.js 107:27-40
Critical dependency: the request of a dependency is an expression
 @ ./node_modules/typeorm/index.js
 @ ./dist/server.module.js
 @ ./dist/main.js

WARNING in ./node_modules/typeorm/platform/PlatformTools.js 112:23-85
Critical dependency: the request of a dependency is an expression
 @ ./node_modules/typeorm/index.js
 @ ./dist/server.module.js
 @ ./dist/main.js

WARNING in ./node_modules/@nestjs/common/utils/load-package.util.js 8:39-59
Critical dependency: the request of a dependency is an expression
 @ ./node_modules/@nestjs/common/serializer/class-serializer.interceptor.js
 @ ./node_modules/@nestjs/common/serializer/index.js
 @ ./node_modules/@nestjs/common/index.js
 @ ./dist/service.module.js
 @ ./dist/main.js

WARNING in ./node_modules/app-root-path/lib/app-root-path.js 14:10-56
Critical dependency: the request of a dependency is an expression
 @ ./node_modules/app-root-path/index.js
 @ ./node_modules/typeorm/platform/PlatformTools.js
 @ ./node_modules/typeorm/index.js
 @ ./dist/server.module.js
 @ ./dist/main.js

WARNING in ./node_modules/parse5/lib/index.js 55:23-49
Critical dependency: the request of a dependency is an expression
 @ ./node_modules/cli-highlight/dist/index.js
 @ ./node_modules/typeorm/platform/PlatformTools.js
 @ ./node_modules/typeorm/index.js
 @ ./dist/server.module.js
 @ ./dist/main.js

WARNING in ./node_modules/express/lib/view.js 81:13-25
Critical dependency: the request of a dependency is an expression
 @ ./node_modules/express/lib/application.js
 @ ./node_modules/express/lib/express.js
 @ ./node_modules/express/index.js
 @ ./node_modules/@nestjs/platform-express/adapters/express-adapter.js
 @ ./node_modules/@nestjs/platform-express/adapters/index.js
 @ ./node_modules/@nestjs/platform-express/index.js
 @ ./dist/service/illumenator.controller.js
 @ ./dist/service/illumenator.module.js
 @ ./dist/service.module.js
 @ ./dist/main.js

WARNING in ./node_modules/@nestjs/core/helpers/load-adapter.js 8:39-63
Critical dependency: the request of a dependency is an expression
 @ ./node_modules/@nestjs/core/nest-factory.js
 @ ./node_modules/@nestjs/core/index.js
 @ ./dist/main.js

WARNING in ./node_modules/optional/optional.js 6:11-26
Critical dependency: the request of a dependency is an expression
 @ ./node_modules/@nestjs/core/nest-application.js
 @ ./node_modules/@nestjs/core/index.js
 @ ./dist/main.js

WARNING in ./node_modules/keyv/src/index.js 18:14-40
Critical dependency: the request of a dependency is an expression
 @ ./node_modules/cacheable-request/src/index.js
 @ ./node_modules/public-ip/node_modules/got/source/request-as-event-emitter.js
 @ ./node_modules/public-ip/node_modules/got/source/as-promise.js
 @ ./node_modules/public-ip/node_modules/got/source/create.js
 @ ./node_modules/public-ip/node_modules/got/source/index.js
 @ ./node_modules/public-ip/index.js
 @ ./dist/service/illumenator.service.js
 @ ./dist/service/illumenator.module.js
 @ ./dist/service.module.js
 @ ./dist/main.js

WARNING in ./node_modules/typeorm/platform/PlatformTools.js
Module not found: Error: Can't resolve 'ioredis' in 'c:\Users\Essential\Documents\kai-brs\node_modules\typeorm\platform'
 @ ./node_modules/typeorm/platform/PlatformTools.js
 @ ./node_modules/typeorm/index.js
 @ ./dist/server.module.js
 @ ./dist/main.js

WARNING in ./node_modules/typeorm/platform/PlatformTools.js
Module not found: Error: Can't resolve 'mongodb' in 'c:\Users\Essential\Documents\kai-brs\node_modules\typeorm\platform'
 @ ./node_modules/typeorm/platform/PlatformTools.js
 @ ./node_modules/typeorm/index.js
 @ ./dist/server.module.js
 @ ./dist/main.js

WARNING in ./node_modules/typeorm/platform/PlatformTools.js
Module not found: Error: Can't resolve 'mysql' in 'c:\Users\Essential\Documents\kai-brs\node_modules\typeorm\platform'
 @ ./node_modules/typeorm/platform/PlatformTools.js
 @ ./node_modules/typeorm/index.js
 @ ./dist/server.module.js
 @ ./dist/main.js

WARNING in ./node_modules/typeorm/platform/PlatformTools.js
Module not found: Error: Can't resolve 'mysql2' in 'c:\Users\Essential\Documents\kai-brs\node_modules\typeorm\platform'
 @ ./node_modules/typeorm/platform/PlatformTools.js
 @ ./node_modules/typeorm/index.js
 @ ./dist/server.module.js
 @ ./dist/main.js

WARNING in ./node_modules/typeorm/platform/PlatformTools.js
Module not found: Error: Can't resolve 'oracledb' in 'c:\Users\Essential\Documents\kai-brs\node_modules\typeorm\platform'
 @ ./node_modules/typeorm/platform/PlatformTools.js
 @ ./node_modules/typeorm/index.js
 @ ./dist/server.module.js
 @ ./dist/main.js

WARNING in ./node_modules/typeorm/platform/PlatformTools.js
Module not found: Error: Can't resolve 'pg' in 'c:\Users\Essential\Documents\kai-brs\node_modules\typeorm\platform'
 @ ./node_modules/typeorm/platform/PlatformTools.js
 @ ./node_modules/typeorm/index.js
 @ ./dist/server.module.js
 @ ./dist/main.js

WARNING in ./node_modules/typeorm/platform/PlatformTools.js
Module not found: Error: Can't resolve 'pg-native' in 'c:\Users\Essential\Documents\kai-brs\node_modules\typeorm\platform'
 @ ./node_modules/typeorm/platform/PlatformTools.js
 @ ./node_modules/typeorm/index.js
 @ ./dist/server.module.js
 @ ./dist/main.js

WARNING in ./node_modules/typeorm/platform/PlatformTools.js
Module not found: Error: Can't resolve 'pg-query-stream' in 'c:\Users\Essential\Documents\kai-brs\node_modules\typeorm\platform'
 @ ./node_modules/typeorm/platform/PlatformTools.js
 @ ./node_modules/typeorm/index.js
 @ ./dist/server.module.js
 @ ./dist/main.js

WARNING in ./node_modules/typeorm/driver/react-native/ReactNativeDriver.js
Module not found: Error: Can't resolve 'react-native-sqlite-storage' in 'c:\Users\Essential\Documents\kai-brs\node_modules\typeorm\driver\react-native'
 @ ./node_modules/typeorm/driver/react-native/ReactNativeDriver.js
 @ ./node_modules/typeorm/driver/DriverFactory.js
 @ ./node_modules/typeorm/connection/Connection.js
 @ ./node_modules/typeorm/connection/ConnectionManager.js
 @ ./node_modules/typeorm/index.js
 @ ./dist/server.module.js
 @ ./dist/main.js

WARNING in ./node_modules/typeorm/platform/PlatformTools.js
Module not found: Error: Can't resolve 'redis' in 'c:\Users\Essential\Documents\kai-brs\node_modules\typeorm\platform'
 @ ./node_modules/typeorm/platform/PlatformTools.js
 @ ./node_modules/typeorm/index.js
 @ ./dist/server.module.js
 @ ./dist/main.js

WARNING in ./node_modules/typeorm/platform/PlatformTools.js
Module not found: Error: Can't resolve 'sql.js' in 'c:\Users\Essential\Documents\kai-brs\node_modules\typeorm\platform'
 @ ./node_modules/typeorm/platform/PlatformTools.js
 @ ./node_modules/typeorm/index.js
 @ ./dist/server.module.js
 @ ./dist/main.js

WARNING in ./node_modules/typeorm/platform/PlatformTools.js
Module not found: Error: Can't resolve 'sqlite3' in 'c:\Users\Essential\Documents\kai-brs\node_modules\typeorm\platform'
 @ ./node_modules/typeorm/platform/PlatformTools.js
 @ ./node_modules/typeorm/index.js
 @ ./dist/server.module.js
 @ ./dist/main.js

ERROR in ./node_modules/@nestjs/core/nest-factory.js
Module not found: Error: Can't resolve '@nestjs/microservices' in 'c:\Users\Essential\Documents\kai-brs\node_modules\@nestjs\core'
 @ ./node_modules/@nestjs/core/nest-factory.js 41:115-147
 @ ./node_modules/@nestjs/core/index.js
 @ ./dist/main.js

ERROR in ./node_modules/@nestjs/core/nest-application.js
Module not found: Error: Can't resolve '@nestjs/microservices' in 'c:\Users\Essential\Documents\kai-brs\node_modules\@nestjs\core'
 @ ./node_modules/@nestjs/core/nest-application.js 101:115-147
 @ ./node_modules/@nestjs/core/index.js
 @ ./dist/main.js

ERROR in ./node_modules/@nestjs/common/cache/cache.providers.js
Module not found: Error: Can't resolve 'cache-manager' in 'c:\Users\Essential\Documents\kai-brs\node_modules\@nestjs\common\cache'
 @ ./node_modules/@nestjs/common/cache/cache.providers.js 10:103-127
 @ ./node_modules/@nestjs/common/cache/cache.module.js
 @ ./node_modules/@nestjs/common/cache/index.js
 @ ./node_modules/@nestjs/common/index.js
 @ ./dist/service.module.js
 @ ./dist/main.js

ERROR in ./node_modules/@nestjs/common/pipes/validation.pipe.js
Module not found: Error: Can't resolve 'class-transformer' in 'c:\Users\Essential\Documents\kai-brs\node_modules\@nestjs\common\pipes'
 @ ./node_modules/@nestjs/common/pipes/validation.pipe.js 43:104-132
 @ ./node_modules/@nestjs/common/pipes/index.js
 @ ./node_modules/@nestjs/common/index.js
 @ ./dist/service.module.js
 @ ./dist/main.js

ERROR in ./node_modules/@nestjs/common/serializer/class-serializer.interceptor.js
Module not found: Error: Can't resolve 'class-transformer' in 'c:\Users\Essential\Documents\kai-brs\node_modules\@nestjs\common\serializer'
 @ ./node_modules/@nestjs/common/serializer/class-serializer.interceptor.js 28:116-144 29:8-36
 @ ./node_modules/@nestjs/common/serializer/index.js
 @ ./node_modules/@nestjs/common/index.js
 @ ./dist/service.module.js
 @ ./dist/main.js

ERROR in ./node_modules/@nestjs/common/pipes/validation.pipe.js
Module not found: Error: Can't resolve 'class-validator' in 'c:\Users\Essential\Documents\kai-brs\node_modules\@nestjs\common\pipes'
 @ ./node_modules/@nestjs/common/pipes/validation.pipe.js 42:100-126
 @ ./node_modules/@nestjs/common/pipes/index.js
 @ ./node_modules/@nestjs/common/index.js
 @ ./dist/service.module.js
 @ ./dist/main.js
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! [email  build:webpack: `rimraf dist && tsc -p tsconfig.build.json && webpack dist/main.js -o dist/main.bundle.js --mode=production`
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the [email  build:webpack script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\Essential\AppData\Roaming\npm-cache\_logs\2019-04-09T09_19_07_825Z-debug.log
The terminal process terminated with exit code: 2

Eller berätta för mig ett bra ramverk för att utveckla Windows-tjänster på Node.js som har scaffold och bygger till en enda fil. (Det är avgörande att paketet inkluderar alla beroenden, det vill säga hela node_modules-mappen, eftersom de datorer som denna tjänst ska installeras på inte har internet för att använda npm)

Svar #1

Jag fick det att fungera med följande 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'),
  },
};

Den del du behöver uppmärksamma här är IgnorePlugin. Nest använder lazy loading för vissa moduler, och webpack kan inte avgöra vilka. checkResource() gör de nödvändiga kontrollerna för de moduler som annars skulle generera fel när du försöker paketera din kod.

Du måste också sätta target: node-alternativet i din konfiguration så att webpack vet att vissa moduler som fs och net stöds nativt i Node (vilket inte är fallet när målet är en webbläsare).

Svar #2

@SergeySovgut: Jag är inte säker på om du har lyckats lägga till den anpassade konfigurationen med webpack än. Men här är en som jag använder för närvarande i mitt projekt

const nodeExternals = require('webpack-node-externals');
var terserPlugin = require('terser-webpack-plugin');
var uglifyJsPlugin = require('uglifyjs-webpack-plugin');
var dotEnvPlugin = require('dotenv-webpack');

module.exports = function(options) {
    return {
        ...options,
        entry: [ './src/main.ts'],
        watch: false,
        resolve: {
            extensions: ['.ts', '.js', '.jade']
        },
        externals: [
            nodeExternals(),
        ],
        module: {
            rules: [
                ...options.module.rules,
                {
                    test: /\.handlebars$/,
                    loader: 'handlebars-loader',
                    options: {
                        knownHelpersOnly: false,
                        inlineRequires: /\/assets\/(:?images|audio|video)\//ig,
                        partialDirs: [path.join(__dirname, './src/views/email/partials')],
                    },
                }
            ]
        },
        plugins: [
            ...options.plugins,
            new webpack.HotModuleReplacementPlugin(),
            new webpack.WatchIgnorePlugin([/\.js$/, /\.d\.ts$/]),
            new dotEnvPlugin({
                path: './config/development/.env',
                safe: true,
                systemvars: true,
                silent: true,
                defaults: false
            }), new webpack.DefinePlugin({
                'process.env.NODE_ENV': 'dev',
                'process.env.DEBUG': 'debug'
            }),new webpack.WatchIgnorePlugin([/\.js$/, /\.d\.ts$/]),
        ],
    };
};

Kort sagt, kommer nest packad med webpack. Vissa av reglerna har förinställts, så till exempel har ts-loader autokonfigurerats för att transpila dina .ts-filer till .js-filer. Så allt vi behöver göra är att utöka de alternativ som redan tillhandahålls av nestjs och sedan skriva vår egen anpassade konfiguration ovanpå det.

Jag tror att de flesta av konfigurationerna är enkla och kan lätt hittas i webpack-dokumentationen

För att köra filen, konfigurera ett skript så här -> `"build:webpack:dev": "rimraf dist && nest build --watch --webpack webpack.dev.config.js"

Sedan kör npm run build:webpack:dev

Mer information här från officiella dokument

Hoppas det hjälper

Relaterade artiklar