从webpack v3迁移到v4后,启动应用程序时出错:
NodeInvocationException:由于错误,预渲染失败: ReferenceError:未定义文档 j:\ PROGETTI \平台\ SOFTWARE \ CTAgenda \ ClientApp \ DIST \主server.js:20159:42
在第20159行的main-server.js中:
/**
* Factory service to easily create a `NgbFocusTrap` instance on an element
*/
var NgbFocusTrapFactory = /** @class */ (function () {
function NgbFocusTrapFactory(_document, _ngZone) {
this._document = _document;
this._ngZone = _ngZone;
}
/**
* Create an instance of {@link NgbFocusTrap} and return it
* @param element HTMLElement to trap focus inside
* @param autofocus Whether the focustrap should automatically move focus into the trapped element upon
* initialization and return focus to the previous activeElement upon destruction.
*/
NgbFocusTrapFactory.prototype.create = function (element, autofocus) {
if (autofocus === void 0) { autofocus = false; }
return new NgbFocusTrap(element, autofocus, this._document, this._ngZone);
};
NgbFocusTrapFactory = __decorate([
core_1.Injectable(),
__param(0, core_1.Inject(common_1.DOCUMENT)),
__metadata("design:paramtypes", [Document, core_1.NgZone]) <-- ERROR
], NgbFocusTrapFactory);
return NgbFocusTrapFactory;
}());
exports.NgbFocusTrapFactory = NgbFocusTrapFactory;
//# sourceMappingURL=focus-trap.js.map
在互联网上看,我明白问题是由使用客户端组件引起的,客户端组件使用文档和窗口,服务器端node.js.从错误消息中可能出现问题,因为@ ng-bootstrap / ng-bootstrap。我也尝试将它从app.module.shared.ts移动到app.module.browser.ts,但没有解决它。鉴于我没有在webpack的第3版中更改应用程序中的任何内容,我无法弄清楚如何解决问题。谢谢您的帮助。
我的环境:
packege.json
{
"name": "aaa",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"buildWPDev": "webpack --config webpack.dev.js",
"buildWPProd": "webpack --config webpack.prod.js",
"initConfig": "webpack-cli init"
},
"private": true,
"dependencies": {
"@angular/animations": "^6.0.0",
"@angular/common": "^6.0.0",
"@angular/compiler": "^6.0.0",
"@angular/core": "^6.0.0",
"@angular/forms": "^6.0.0",
"@angular/http": "^6.0.0",
"@angular/platform-browser": "^6.0.0",
"@angular/platform-browser-dynamic": "^6.0.0",
"@angular/platform-server": "^6.0.0",
"@angular/router": "^6.0.0",
"@ng-bootstrap/ng-bootstrap": "^2.0.0",
"aspnet-prerendering": "^3.0.1",
"aspnet-webpack": "^2.0.3",
"bootstrap": "^4.1.1",
"css": "2.2.3",
"es6-shim": "0.35.3",
"event-source-polyfill": "0.0.12",
"isomorphic-fetch": "2.2.1",
"jquery": "3.3.1",
"jwt-decode": "^2.2.0",
"material-design-icons": "^3.0.1",
"moment": "^2.22.1",
"ngx-toastr": "^8.5.0",
"nodemailer": "^4.6.4",
"popper.js": "^1.14.3",
"preboot": "6.0.0-beta.4",
"reflect-metadata": "0.1.12",
"rxjs": "^6.1.0",
"rxjs-compat": "^6.1.0",
"stacktrace-js": "^2.0.0",
"zone.js": "^0.8.26"
},
"devDependencies": {
"@angular/cli": "^6.0.0",
"@angular/compiler-cli": "^6.0.0",
"@angular/language-service": "^6.0.0",
"@ngtools/webpack": "^6.0.0",
"@types/chai": "4.1.3",
"@types/jasmine": "2.8.7",
"@types/jasminewd2": "~2.0.3",
"@types/node": "~10.0.4",
"@types/stacktrace-js": "0.0.32",
"@types/webpack-env": "^1.13.6",
"angular-router-loader": "^0.8.5",
"angular2-template-loader": "^0.6.2",
"chai": "4.1.2",
"codelyzer": "~4.3.0",
"css-loader": "^0.28.11",
"file-loader": "^1.1.11",
"html-loader": "^0.5.5",
"jasmine-core": "3.1.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "2.0.0",
"karma-chai": "0.1.0",
"karma-chrome-launcher": "2.2.0",
"karma-cli": "1.0.1",
"karma-coverage-istanbul-reporter": "^1.4.1",
"karma-jasmine": "1.1.1",
"karma-jasmine-html-reporter": "^0.2.2",
"karma-webpack": "^3.0.0",
"mini-css-extract-plugin": "^0.4.0",
"ng-router-loader": "^2.1.0",
"protractor": "~5.3.1",
"style-loader": "^0.21.0",
"to-string-loader": "^1.1.5",
"ts-loader": "^4.3.0",
"ts-node": "~6.0.3",
"tslint": "^5.10.0",
"typescript": "^2.7.2",
"uglifyjs-webpack-plugin": "^1.2.5",
"url-loader": "^1.0.1",
"webpack": "^4.8.1",
"webpack-cli": "^2.1.3",
"webpack-hot-middleware": "^2.22.1",
"webpack-merge": "^4.1.2"
}
}
webpack.config.vendor.js
const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const merge = require('webpack-merge');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const treeShakableModules = [
'@angular/animations',
'@angular/common',
'@angular/compiler',
'@angular/core',
'@angular/forms',
'@angular/http',
'@angular/platform-browser',
'@angular/platform-browser-dynamic',
'@angular/router',
'zone.js'
];
const nonTreeShakableModules = [
'bootstrap',
'bootstrap/dist/css/bootstrap.css',
'es6-shim',
'event-source-polyfill',
"ngx-toastr",
"ngx-toastr/toastr.css",
'jquery'
];
const allModules = treeShakableModules.concat(nonTreeShakableModules);
module.exports = (env) => {
const isDevBuild = !(env && env.prod);
const sharedConfig = {
mode: isDevBuild ? 'development' : 'production',
stats: {
modules: false
},
resolve: {
extensions: ['.js']
},
module: {
rules: [{
test: /\.(png|woff|woff2|eot|ttf|svg)(\?|$)/,
use: [{
loader: 'url-loader',
options: {
limit: 25000,
fallback: 'file-loader'
}
}]
}]
},
output: {
publicPath: 'dist/',
filename: '[name].js',
library: '[name]_[hash]'
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}), // Maps these identifiers to the jQuery package (because Bootstrap expects it to be a global variable)
//new webpack.ContextReplacementPlugin(/\@angular\b.*\b(bundles|linker)/, path.join(__dirname, './ClientApp')), // Workaround for https://github.com/angular/angular/issues/11580
new webpack.ContextReplacementPlugin(/(.+)?angular(\\|\/)core(.+)?/, path.resolve(__dirname, './ClientApp')) //,
//new webpack.IgnorePlugin(/^vertx$/) // Workaround for https://github.com/stefanpenner/es6-promise/issues/100
]
};
const clientBundleConfig = merge(sharedConfig, {
entry: {
// To keep development builds fast, include all vendor dependencies in the vendor bundle.
// But for production builds, leave the tree-shakable ones out so the AOT compiler can produce a smaller bundle.
vendor: isDevBuild ? allModules : nonTreeShakableModules
},
output: {
path: path.join(__dirname, 'wwwroot', 'dist')
},
module: {
rules: [{
test: /\.css(\?|$)/,
use: [{
loader: MiniCssExtractPlugin.loader
},
{
loader: 'css-loader'
}
]
}]
},
plugins: [
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: "vendor.css"
}),
new webpack.DllPlugin({
context: __dirname,
path: path.join(__dirname, 'wwwroot', 'dist', '[name]-manifest.json'),
name: '[name]_[hash]'
})
].concat(isDevBuild ? [] : [
new UglifyJsPlugin()
])
});
const serverBundleConfig = merge(sharedConfig, {
target: 'node',
resolve: {
mainFields: ['main']
},
entry: {
vendor: allModules.concat(['aspnet-prerendering'])
},
output: {
path: path.join(__dirname, 'ClientApp', 'dist'),
libraryTarget: 'commonjs2',
},
module: {
rules: [{
test: /\.css(\?|$)/,
use: ['to-string-loader', 'css-loader']
}]
},
plugins: [
new webpack.DllPlugin({
context: __dirname,
path: path.join(__dirname, 'ClientApp', 'dist', '[name]-manifest.json'),
name: '[name]_[hash]'
})
]
});
return [clientBundleConfig, serverBundleConfig];
}
webpack.common.js
module.exports = {
output: {
filename: '[name].js',
publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
resolve: {
extensions: ['.js', '.ts']
},
stats: {
modules: false
},
context: __dirname,
module: {
rules: [
{
test: /\.(png|jpg|jpeg|gif|svg)$/,
use: [{
loader: 'url-loader',
options: {
limit: 25000,
fallback: 'file-loader'
}
}]
},
{
test: /\.html$/,
use: {
loader: 'html-loader',
options: {
minimize: false
}
}
}
]
}
};
webpack.dev.js
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
// Configuration in common to both client-side and server-side bundles
const clientBundleOutputDir = './wwwroot/dist';
const serverBundleOutputDir = './ClientApp/dist';
const sharedConfig = {
module: {
rules: [
{
test: /\.css$/,
use: ['to-string-loader', 'css-loader']
},
{
test: /\.ts$/,
include: /ClientApp/,
use: [{
loader: 'ng-router-loader'
},
{
loader: 'ts-loader',
options: {
silent: true
}
},
{
loader: 'angular2-template-loader'
}
]
},
{
test: /\.(ts|js)$/,
include: /ClientApp/,
use: {
loader: 'angular-router-loader'
}
}
]
},
mode: 'development'
};
// Configuration for client-side bundle suitable for running in browsers
const clientConfig = merge(sharedConfig, {
entry: {
'main-client': './ClientApp/boot.browser.ts'
},
output: {
path: path.join(__dirname, clientBundleOutputDir)
},
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat([
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
])
});
// Configuration for server-side (prerendering) bundle suitable for running in Node
const serverConfig = merge(sharedConfig, {
entry: {
'main-server': './ClientApp/boot.server.ts'
},
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, serverBundleOutputDir)
},
resolve: {
mainFields: ['main']
},
target: 'node',
devtool: 'inline-source-map',
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./ClientApp/dist/vendor-manifest.json'),
sourceType: 'commonjs2',
name: './vendor'
})
]
});
module.exports = () => {
const clientBundleConfig = merge(commonConfig, clientConfig);
const serverBundleConfig = merge(commonConfig, serverConfig);
return [clientBundleConfig, serverBundleConfig];
};
startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
{
HotModuleReplacement = true,
ConfigFile = "webpack.dev.js"
});
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
}
index.cshtml
@{
ViewData["Title"] = "Home Page";
}
<app asp-prerender-module="ClientApp/dist/main-server">Loading...</app>
<script src="~/dist/vendor.js" asp-append-version="true"></script>
@section scripts {
<script src="~/dist/main-client.js" asp-append-version="true"></script>
}
boot.server.ts
import { enableProdMode, ApplicationRef, NgZone } from '@angular/core';
import { APP_BASE_HREF } from '@angular/common';
import { platformDynamicServer, PlatformState, INITIAL_CONFIG } from '@angular/platform-server';
import { first } from 'rxjs/operators';
import 'reflect-metadata';
import 'zone.js';
import { createServerRenderer, RenderResult } from 'aspnet-prerendering';
import { AppModule } from './app/app.module.server';
enableProdMode();
export default createServerRenderer(params => {
const providers = [
{ provide: INITIAL_CONFIG, useValue: { document: '<app></app>', url: params.url } },
{ provide: APP_BASE_HREF, useValue: params.baseUrl },
{ provide: 'BASE_URL', useValue: params.origin + params.baseUrl },
];
return platformDynamicServer(providers).bootstrapModule(AppModule).then(moduleRef => {
const appRef: ApplicationRef = moduleRef.injector.get(ApplicationRef);
const state = moduleRef.injector.get(PlatformState);
const zone: NgZone = moduleRef.injector.get(NgZone);
return new Promise<RenderResult>((resolve, reject) => {
zone.onError
.subscribe((errorInfo: any) => reject(errorInfo));
appRef.isStable
.pipe(
first(isStable => isStable)
)
.subscribe(() => {
// Because 'onStable' fires before 'onError', we have to delay slightly before
// completing the request in case there's an error to report
setImmediate(() => {
resolve({
html: state.renderToString()
});
moduleRef.destroy();
});
});
});
});
});
app.module.shared.ts
import { CommonModule } from '@angular/common';
import { ErrorHandler } from '@angular/core';
import { NgModule } from '@angular/core';
import { NgbModule, NgbDateAdapter, NgbDateParserFormatter } from '@ng-bootstrap/ng-bootstrap';
import { ToastrModule, ToastContainerModule } from 'ngx-toastr';
import { AppRoutingModule } from './app-routing.module';
import { AppErrorHandler } from './app.error-handler';
import { AppSessionStorage } from './models/shared.model';
import { AppComponent } from './components/app/app.component';
import { ClinicalTrialsModule } from './components/clinicalTrials/clinicalTrials.module';
import { HomeModule } from './components/home/home.module';
import { ErrorModule } from './components/error/error.module';
import { LoginModule } from './components/login/login.module';
import { NavMenuModule } from './components/navmenu/navmenu.module';
import { ToolbarModule } from './components/toolbar/toolbar.module';
import { TrackingsModule } from './components/trackings/trackings.module';
import { GuardsModule } from './guards/guards.module';
import { ServicesModule } from './services/services.module';
import { InterceptorsModule } from './interceptors/interceptors.module';
import { NgbDateNativeAdapter } from './extensions/ngbDateAdapter.extension';
import { NgbDateGeneralParserFormatter } from './extensions/ngbDateParserFormatter.extension';
@NgModule({
imports: [
CommonModule,
GuardsModule,
InterceptorsModule,
ServicesModule,
NavMenuModule,
ToolbarModule,
HomeModule, /* with Routing */
ErrorModule, /* with Routing */
LoginModule, /* with Routing */
ClinicalTrialsModule, /* with Routing */
TrackingsModule,
AppRoutingModule, /* with Routing */
ToastrModule.forRoot({
positionClass: 'toast-top-center',
timeOut: 7000,
preventDuplicates: true
}),
ToastContainerModule,
NgbModule.forRoot()
],
declarations: [
AppComponent
],
providers: [
{ provide: ErrorHandler, useClass: AppErrorHandler },
{ provide: AppSessionStorage, useValue: { getItem() { } } },
{ provide: NgbDateAdapter, useClass: NgbDateNativeAdapter },
{ provide: NgbDateParserFormatter, useClass: NgbDateGeneralParserFormatter }
]
})
export class AppModuleShared {
}
app.module.server.ts
import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { AppModuleShared } from './app.module.shared';
import { AppComponent } from './components/app/app.component';
@NgModule({
bootstrap: [ AppComponent ],
imports: [
ServerModule,
AppModuleShared
]
})
export class AppModule {
}
答案 0 :(得分:0)
我找到了问题的根源:在我写作时,@ ng-bootstrap / ng-bootstrap与Angular 6的最新版本不完全兼容。
正如Zoran Ivancevic(@zolakt)建议的那样,可以使用一种解决方法,将新的webpack.DefinePlugin({'Document':null})添加到webpack配置文件中。