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';
现在可以构建了