Angular SSR + webpack

Angular SSR + webpack

我正在做一个 angular 项目,

版本:

-Angular CLI:8.3.29
-节点:12.14.1
-Angular: 8.2.14

我需要在其上应用侧面渲染,我使用以下命令在我的项目上设置 angular univeral

npm install @nguniversal/express-engine --save

解决了很多问题(构建、闪烁、双重加载页面...)后,我现在可以使用

在我的本地环境中启动它
build:ssr && serve:ssr

但是当我尝试在生产服务器上部署它时,在生产服务器上构建项目之后,当我尝试使用 node /dist/server/main.js

启动服务器时

我收到以下错误

Error: Cannot find module 'zone.js/dist/zone-node'

我在论坛上搜索,发现我必须使用 webpack 构建我的服务器端代码

所以我将 package.json 更新为

"dev:ssr": "ng run my-app-name:serve-ssr",
"serve:ssr": "node dist/server.js",
"build:client-and-server-bundles": "ng build --prod && ng run my-app-name:server:production",
"build-wp:ssr": "npm run build:client-and-server-bundles && npm run webpack:server",
"webpack:server": "webpack --config webpack.server.config.js --progress --colors"

webpack.server.config.js

const path = require('path');
const webpack = require('webpack');

module.exports = {
  mode: 'none',
  entry: {
    // This is our Express server for Dynamic universal
    server: './server.ts'
  },
  externals: {
    './dist/server/main': 'require("./server/main")'
  },
  target: 'node',
  resolve: { extensions: ['.ts', '.js'] },
  optimization: {
    minimize: false
  },
  output: {
    // Puts the output at the root of the dist folder
    path: path.join(__dirname, 'dist'),
    filename: '[name].js'
  },
  module: {
    noParse: /polyfills-.*\.js/,
    rules: [
      { test: /\.ts$/, loader: 'ts-loader' },
      {
        // Mark files inside `@angular/core` as using SystemJS style dynamic imports.
        // Removing this will cause deprecation warnings to appear.
        test: /(\|\/)@angular(\|\/)core(\|\/).+\.js$/,
        parser: { system: true },
      },
    ]
  },
  plugins: [
    new webpack.ContextReplacementPlugin(
      // fixes WARNING Critical dependency: the request of a dependency is an expression
      /(.+)?angular(\|\/)core(.+)?/,
      path.join(__dirname, 'src'), // location of your src
      {} // a map of your routes
    ),
    new webpack.ContextReplacementPlugin(
      // fixes WARNING Critical dependency: the request of a dependency is an expression
      /(.+)?express(\|\/)(.+)?/,
      path.join(__dirname, 'src'),
      {}
    )
  ]
};

server.ts

import 'zone.js/dist/zone-node';

import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';

import { AppServerModule } from './src/main.server';
import { APP_BASE_HREF } from '@angular/common';
import { existsSync } from 'fs';

// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
  const server = express();
  const distFolder = join(process.cwd(), 'dist/browser');
  const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';


  const DIST_FOLDER = join(process.cwd(), 'dist');

  // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
  server.engine('html', ngExpressEngine({
    bootstrap: AppServerModule,
  }));

  server.set('view engine', 'html');
  server.set('views', join(DIST_FOLDER, 'browser'));
  //server.set('views', distFolder);

  // Example Express Rest API endpoints
  // server.get('/api/**', (req, res) => { });
  // Serve static files from /browser
  server.get('*.*', express.static(distFolder, {
    maxAge: '1y'
  }));

  // All regular routes use the Universal engine
  server.get('*', (req, res) => {
    res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
  });

  return server;
}

function run(): void {
  const port = process.env.PORT || 4200;

  // Start up the Node server
  const server = app();
  server.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`);
  });
}

// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
  run();
}

export * from './src/main.server';

angular.json

{
      "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
      "version": 1,
      "newProjectRoot": "projects",
      "projects": {
        "my-app-name": {
          "root": "",
          "sourceRoot": "src",
          "projectType": "application",
          "prefix": "app",
          "schematics": {
            "@schematics/angular:component": {
              "styleext": "scss"
            }
          },
          "architect": {
            "build": {
              "builder": "@angular-devkit/build-angular:browser",
              "options": {
                "outputPath": "dist/browser",
                "index": "src/index.html",
                "main": "src/main.ts",
                "polyfills": "src/polyfills.ts",
                "tsConfig": "src/tsconfig.app.json",
                "assets": [
                  "src/favicon.ico",
                  "src/assets"
                ],
                "styles": [
                  "src/assets/sass/main.scss",
                  "node_modules/bootstrap/scss/bootstrap.scss"
                ],
                "scripts": []
              },
              "configurations": {
                "production": {
                  "fileReplacements": [
                    {
                      "replace": "src/environments/environment.ts",
                      "with": "src/environments/environment.prod.ts"
                    }
                  ],
                  "optimization": true,
                  "outputHashing": "all",
                  "sourceMap": false,
                  "extractCss": true,
                  "namedChunks": false,
                  "aot": true,
                  "extractLicenses": true,
                  "vendorChunk": false,
                  "buildOptimizer": true
                }
              }
            },
            "serve": {
              "builder": "@angular-devkit/build-angular:dev-server",
              "options": {
                "browserTarget": "my-app-name:build",
                "sslKey": "ssl/server.key",
                "sslCert": "ssl/server.crt"
              },
              "configurations": {
                "production": {
                  "browserTarget": "my-app-name:build:production"
                }
              }
            },
            "server": {
              "builder": "@angular-devkit/build-angular:server",
              "options": {
                "outputPath": "dist/server",
                "main": "server.ts",
                "tsConfig": "src/tsconfig.server.json"
              },
              "configurations": {
                "production": {
                  "outputHashing": "media",
                  "fileReplacements": [
                    {
                      "replace": "src/environments/environment.ts",
                      "with": "src/environments/environment.prod.ts"
                    }
                  ],
                  "sourceMap": false,
                  "optimization": {
                    "scripts": false,
                    "styles": true
                  }
                }
              }
            },
            "serve-ssr": {
              "builder": "@nguniversal/builders:ssr-dev-server",
              "options": {
                "browserTarget": "my-app-name:build",
                "serverTarget": "my-app-name:server"
              },
              "configurations": {
                "production": {
                  "browserTarget": "my-app-name:build:production",
                  "serverTarget": "my-app-name:server:production"
                }
              }
            },
            "prerender": {
              "builder": "@nguniversal/builders:prerender",
              "options": {
                "browserTarget": "my-app-name:build:production",
                "serverTarget": "my-app-name:server:production",
                "routes": [
                  "/"
                ]
              },
              "configurations": {
                "production": {}
              }
            }
          }
        },
      },
      "defaultProject": "my-app-name"
    }

现在当我播放命令时

webpack:server

我遇到了很多这样的错误:

ERROR in ./src/app/components/auth/login/login.component.ts Module not found: Error: Can't resolve 'src/app/web-services/facebook-sdk.service' in 'C:\Code\my-app-name\src\app\components\auth\login' @ ./src/app/components/auth/login/login.component.ts 21:0-79 140:8-26 @ ./src/app/components/auth/login/login.module.ts @ ./src/app/app-routing.module.ts @ ./src/app/app.module.ts @ ./src/app/app.server.module.ts @ ./src/main.server.ts @ ./server.ts

我不知道如何找到问题出在哪里,是不是在我的配置中某处有错误值的路径?

我检查了几个小时,但找不到错误。

请帮帮我!!!!

提前谢谢你

亚历克斯

我发现了问题:

在我的组件和模块中,我使用了带有相对路径的导入

import { ApiClientService } from 'src/app/web-services/api-client.service';

我改成了绝对路径

import { ApiClientService } from '../../web-services/api-client.service';

现在可以构建了