diff --git a/README.md b/README.md new file mode 100644 index 0000000..96e55e9 --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +# Angular Universal & Anguar-CLI minimal starter + +> This demo is built following the [Angular-CLI Wiki guide](https://github.com/angular/angular-cli/wiki/stories-universal-rendering) + +We're utilizing packages from the [Angular Universal @nguniversal](https://github.com/angular/universal) repo, such as [ng-module-map-ngfactory-loader](https://github.com/angular/universal/tree/master/modules/module-map-ngfactory-loader) to enable Lazy Loading. + +--- + +## Static or Dynamic +This repo demonstrates the use of 2 different forms of Server Side Rendering. + +**Static** Also known as "prerendering" +* Happens at build time +* Renders your application and replaces the dist index.html with a version rendered at the route `/`. + +**Dynamic** +* Happens at runtime +* Uses `ngExpressEngine` to render you application on the fly at the requested url. + +--- + +## Installation +* `npm install` or `yarn` + +--- + +## Development (Client-side only rendering) +* run `npm run start` which will start `ng serve` (project served at the standard: localhost:4200) + +--- + +## Production + +Depending on whether you're publishing dynamic or static prerendering, run the build command, and then serve up your dist folder assets. + +> **NOTE**: To deploy your **Static** site to a static hosting platform you will have to deploy the *`dist/browser`* folder, rather than the usual *`dist`* + +ie: `npm run build:dynamic` or `npm run build:static`. All of the files that need to be served will be found within the `/dist` folder. + + + +--- + +## Testing Universal (dynamic or static) builds -Locally- + +**Dynamic** : **`npm run start:dynamic`** + +Compiles your application and spins up a Node Express to dynamically serve your Universal application on `http://localhost:4000`. + +**Static** : **`npm run start:static`** + +- Compiles your application and prerenders your applications files, spinning up a demo http-server so you can view it on `http://127.0.0.1:8080` + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..4033b2a --- /dev/null +++ b/package.json @@ -0,0 +1,73 @@ +{ + "name": "openaire-monitor", + "version": "1.0.0", + "license": "Openaire", + "contributors": [ + "Argiro Kokogiannaki ", + "Konstantina Galouni " + ], + "scripts": { + "ng": "ng", + "start": " ng serve --disable-host-check --host 0.0.0.0", + "start:ssr": "npm run build:ssr && npm run serve:ssr", + "start:prerender": "npm run build:prerender && npm run serve:prerender", + "build": "ng build", + "build:client-and-server-bundles": "ng build --prod --sourceMap --stats-json=true && ng run ng-universal-demo:server:production", + "build:prerender": "npm run build:client-and-server-bundles && npm run webpack:server && npm run generate:prerender", + "build:ssr": "npm run build:client-and-server-bundles && npm run webpack:server", + "generate:prerender": "cd dist && node prerender", + "webpack:server": "webpack --config webpack.server.config.js --progress --colors", + "serve:prerender": "cd dist/browser && http-server", + "serve:ssr": "node dist/server" + }, + "private": true, + "dependencies": { + "@angular/animations": "^7.2.14", + "@angular/cdk": "^7.3.7", + "@angular/common": "7.2.14", + "@angular/compiler": "7.2.14", + "@angular/core": "7.2.14", + "@angular/forms": "7.2.14", + "@angular/http": "7.2.14", + "@angular/material": "^7.3.7", + "@angular/platform-browser": "7.2.14", + "@angular/platform-browser-dynamic": "7.2.14", + "@angular/platform-server": "7.2.14", + "@angular/router": "7.2.14", + "@nguniversal/express-engine": "^6.0.0", + "@nguniversal/module-map-ngfactory-loader": "^6.0.0", + "@types/express": "^4.16.1", + "angular-datatables": "^4.4.1", + "citation-js": "^0.3.4", + "clipboard": "^1.5.16", + "core-js": "^2.4.1", + "datatables.net": "^1.10.19", + "datatables.net-dt": "^1.10.19", + "jquery": "^3.4.1", + "ngx-json-ld": "0.1.6", + "prom-client": "^11.3.0", + "ts-md5": "^1.2.0", + "tslib": "^1.9.0", + "wikidata-sdk": "^5.2.9", + "zone.js": "^0.8.26", + "ng-recaptcha": "^3.0.5", + "ng2-ckeditor": "1.1.9" + }, + "devDependencies": { + "@angular-devkit/build-angular": "~0.13.0", + "@angular/cli": "^7.3.9", + "@angular/compiler-cli": "7.2.14", + "@angular/language-service": "7.2.14", + "@types/datatables.net": "^1.10.17", + "@types/jquery": "^3.3.29", + "@types/node": "^8.0.30", + "cpy-cli": "^1.0.1", + "http-server": "^0.10.0", + "reflect-metadata": "^0.1.10", + "rxjs": "6.5.1", + "rxjs-compat": "^6.5.1", + "ts-loader": "^4.2.0", + "typescript": "3.2.4", + "webpack-cli": "^3.3.2" + } +} diff --git a/prerender.ts b/prerender.ts new file mode 100644 index 0000000..c664006 --- /dev/null +++ b/prerender.ts @@ -0,0 +1,45 @@ +// Load zone.js for the server. +import 'zone.js/dist/zone-node'; +import 'reflect-metadata'; +import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs'; +import { join } from 'path'; + +import { enableProdMode } from '@angular/core'; +// Faster server renders w/ Prod mode (dev mode never needed) +enableProdMode(); + +// Express Engine +import { ngExpressEngine } from '@nguniversal/express-engine'; +// Import module map for lazy loading +import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader'; +import { renderModuleFactory } from '@angular/platform-server'; +import { ROUTES } from './static.paths'; + +// * NOTE :: leave this as require() since this file is built Dynamically from webpack +const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main'); + +const BROWSER_FOLDER = join(process.cwd(), 'browser'); + +// Load the index.html file containing referances to your application bundle. +const index = readFileSync(join('browser', 'index.html'), 'utf8'); + +let previousRender = Promise.resolve(); + +// Iterate each route path +ROUTES.forEach(route => { + const fullPath = join(BROWSER_FOLDER, route); + + // Make sure the directory structure is there + if(!existsSync(fullPath)){ + mkdirSync(fullPath); + } + + // Writes rendered HTML to index.html, replacing the file if it already exists. + previousRender = previousRender.then(_ => renderModuleFactory(AppServerModuleNgFactory, { + document: index, + url: route, + extraProviders: [ + provideModuleMap(LAZY_MODULE_MAP) + ] + })).then(html => writeFileSync(join(fullPath, 'index.html'), html)); +}); diff --git a/server.ts b/server.ts new file mode 100644 index 0000000..fd35820 --- /dev/null +++ b/server.ts @@ -0,0 +1,71 @@ +import 'zone.js/dist/zone-node'; +import 'reflect-metadata'; +import { renderModuleFactory } from '@angular/platform-server'; +import { enableProdMode } from '@angular/core'; + +import * as express from 'express'; +import { join } from 'path'; +import { readFileSync } from 'fs'; + +// Faster server renders w/ Prod mode (dev mode never needed) +enableProdMode(); + +// Express server +const app = express(); + +const PORT = process.env.PORT || 4000; +const DIST_FOLDER = join(process.cwd(), 'dist'); + +// Our index.html we'll use as our template +const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html')).toString(); + +// * NOTE :: leave this as require() since this file is built Dynamically from webpack +const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main'); + +// Express Engine +import {ngExpressEngine, RenderOptions} from '@nguniversal/express-engine'; +// Import module map for lazy loading +import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader'; + +// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine) +// app.engine('html', ngExpressEngine({ +// bootstrap: AppServerModuleNgFactory, +// providers: [ +// { provide: 'request', useFactory: () => options.req, deps: [] }, +// provideModuleMap(LAZY_MODULE_MAP) +// ] +// })); + +// be able to get request and get domain from there +app.engine('html', (_, options: RenderOptions, callback) => { + let engine = ngExpressEngine({ + bootstrap: AppServerModuleNgFactory, + providers: [ + { provide: 'request', useFactory: () => options.req, deps: [] }, + provideModuleMap(LAZY_MODULE_MAP) + ] + }); + engine(_, options, callback); +}); + +app.set('view engine', 'html'); +app.set('views', join(DIST_FOLDER, 'browser')); + +/* - Example Express Rest API endpoints - + app.get('/api/**', (req, res) => { }); +*/ + +// Server static files from /browser +app.get('*.*', express.static(join(DIST_FOLDER, 'browser'), { + maxAge: '1y' +})); + +// ALl regular routes use the Universal engine +app.get('*', (req, res) => { + res.render('index', { req }); +}); + +// Start up the Node server +app.listen(PORT, () => { + console.log(`Node Express server listening on http://localhost:${PORT}`); +}); diff --git a/src/app/app.module.ts b/src/app/app.module.ts new file mode 100755 index 0000000..e6bc615 --- /dev/null +++ b/src/app/app.module.ts @@ -0,0 +1,46 @@ +import {NgModule} from '@angular/core'; +import {FormsModule} from '@angular/forms'; +import {CommonModule} from '@angular/common'; +import {HttpClientModule} from "@angular/common/http"; +import {BrowserModule} from '@angular/platform-browser'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {AppComponent} from './app.component'; +import {OpenaireErrorPageComponent} from './error/errorPage.component'; + +import {AppRoutingModule} from './app-routing.module'; +import {SharedModule} from './shared/shared.module'; +import {CookieLawModule} from './openaireLibrary/sharedComponents/cookie-law/cookie-law.module'; +import {BottomModule} from './openaireLibrary/sharedComponents/bottom.module'; +import {ErrorModule} from './openaireLibrary/error/error.module'; +import {NavigationBarModule} from './openaireLibrary/sharedComponents/navigationBar.module'; + +import {EnvironmentSpecificResolver} from './openaireLibrary/utils/properties/environmentSpecificResolver'; + +import {CommunitiesService} from './openaireLibrary/connect/communities/communities.service'; +import {LayoutService} from "./openaireLibrary/services/layout.service"; +import {SubscribeModule} from './utils/subscribe/subscribe.module'; +import {ThemeComponent} from "./test/theme.component"; + +@NgModule({ + + imports: [ + SharedModule, + NoopAnimationsModule, + CommonModule, + HttpClientModule, + ErrorModule, + FormsModule, + NavigationBarModule, + BottomModule, + CookieLawModule, + SubscribeModule.forRoot(), + BrowserModule.withServerTransition({appId: 'my-app'}), + AppRoutingModule + ], + declarations: [ AppComponent, OpenaireErrorPageComponent, ThemeComponent], + exports: [ AppComponent ], + providers:[EnvironmentSpecificResolver, CommunitiesService, LayoutService], + bootstrap: [AppComponent] +}) +// +export class AppModule {} diff --git a/src/app/app.server.module.ts b/src/app/app.server.module.ts new file mode 100644 index 0000000..79602ec --- /dev/null +++ b/src/app/app.server.module.ts @@ -0,0 +1,20 @@ +import {NgModule} from '@angular/core'; +import {ServerModule} from '@angular/platform-server'; +import {ModuleMapLoaderModule} from '@nguniversal/module-map-ngfactory-loader'; + +import {AppModule} from './app.module'; +import {AppComponent} from './app.component'; + +@NgModule({ + imports: [ + // The AppServerModule should import your AppModule followed + // by the ServerModule from @angular/platform-server. + AppModule, + ServerModule, + ModuleMapLoaderModule, + ], + // Since the bootstrapped component is not inherited from your + // imported AppModule, it needs to be repeated here. + bootstrap: [AppComponent], +}) +export class AppServerModule {} diff --git a/src/app/error/errorPage.component.ts b/src/app/error/errorPage.component.ts new file mode 100644 index 0000000..e96d3dc --- /dev/null +++ b/src/app/error/errorPage.component.ts @@ -0,0 +1,13 @@ +import { Component, Input } from '@angular/core'; +import { Location } from '@angular/common'; + +@Component({ + selector: 'openaire-error', + template: ` + + ` +}) + +export class OpenaireErrorPageComponent { + +} diff --git a/src/app/home/home-routing.module.ts b/src/app/home/home-routing.module.ts new file mode 100644 index 0000000..099e07c --- /dev/null +++ b/src/app/home/home-routing.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import{HomeComponent} from './home.component'; + +import {FreeGuard} from '../openaireLibrary/login/freeGuard.guard'; +import {PreviousRouteRecorder} from '../openaireLibrary/utils/piwik/previousRouteRecorder.guard'; + +@NgModule({ + imports: [ + RouterModule.forChild([ + { path: '', component: HomeComponent, canActivate: [FreeGuard], canDeactivate: [PreviousRouteRecorder] } + + ]) + ] +}) +export class HomeRoutingModule { } diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html new file mode 100644 index 0000000..654c699 --- /dev/null +++ b/src/app/home/home.component.html @@ -0,0 +1,242 @@ + + +
+ + +
+
+ + +
+
+ +
+
+
Community Gateways in Action
+
+ +
+
+
+ +
+
+
+ +
+ +
+ + +
+
+ +
+
diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts new file mode 100644 index 0000000..f93f75e --- /dev/null +++ b/src/app/home/home.component.ts @@ -0,0 +1,199 @@ +import {Component} from '@angular/core'; +import {ActivatedRoute, Router} from '@angular/router'; +import {Meta, Title} from '@angular/platform-browser'; +import {EnvProperties} from '../openaireLibrary/utils/properties/env-properties'; +import {CommunitiesService} from '../openaireLibrary/connect/communities/communities.service'; +import {SubscribeService} from '../openaireLibrary/utils/subscribe/subscribe.service'; +import {CommunityInfo} from '../openaireLibrary/connect/community/communityInfo'; + +import {PiwikService} from '../openaireLibrary/utils/piwik/piwik.service'; +import {StringUtils} from '../openaireLibrary/utils/string-utils.class'; + +import {ErrorCodes} from '../openaireLibrary/utils/properties/errorCodes'; +import {ErrorMessagesComponent} from '../openaireLibrary/utils/errorMessages.component'; +import {HelperService} from "../openaireLibrary/utils/helper/helper.service"; +import {SEOService} from "../openaireLibrary/sharedComponents/SEO/SEO.service"; + +@Component({ + selector: 'home', + templateUrl: 'home.component.html', +}) + +export class HomeComponent { + public piwiksub: any; + + public pageTitle = "OpenAIRE | Monitor"; + public researchCommunities = []; + public gifs: { "gif": string, "header": string, "text" }[] = []; + public pageContents = null; + public divContents = null; + // Message variables + public status: number; + public loading: boolean = true; + public subscriberErrorMessage: string = ""; + public errorCodes: ErrorCodes; + private errorMessages: ErrorMessagesComponent; + + properties: EnvProperties; + public keyword: string = ""; + public type: string = "all"; + + constructor( + private route: ActivatedRoute, + private _router: Router, + private _meta: Meta, + private _title: Title, + private _piwikService: PiwikService, + private _communitiesService: CommunitiesService, + private _subscribeService: SubscribeService, + private helper: HelperService, + private seoService: SEOService) { + + var description = "OpenAIRE - Monitor, monitor dashboard, funder, statistics, "; + var title = "OpenAIRE - Monitor"; + + this._meta.updateTag({content: description}, "name='description'"); + this._meta.updateTag({content: description}, "property='og:description'"); + this._meta.updateTag({content: title}, "property='og:title'"); + this._title.setTitle(title); + + this.errorCodes = new ErrorCodes(); + this.errorMessages = new ErrorMessagesComponent(); + this.status = this.errorCodes.LOADING; + } + + public ngOnInit() { + this.route.data + .subscribe((data: { envSpecific: EnvProperties }) => { + this.properties = data.envSpecific; + var url = data.envSpecific.baseLink + this._router.url; + this.seoService.createLinkForCanonicalURL(url, false); + this._meta.updateTag({content: url}, "property='og:url'"); + if (this.properties.enablePiwikTrack && (typeof document !== 'undefined')) { + this.piwiksub = this._piwikService.trackView(this.properties, "OpenAIRE Monitor", this.properties.piwikSiteId).subscribe(); + } + this.getCommunities(); + this.createGifs(); + //this.getDivContents(); + this.getPageContents(); + }); + } + + private getPageContents() { + this.helper.getPageHelpContents(this._router.url, this.properties, 'monitor').subscribe(contents => { + this.pageContents = contents; + }) + } + + private getDivContents() { + this.helper.getDivHelpContents(this._router.url, this.properties, 'monitor').subscribe(contents => { + this.divContents = contents; + }) + } + + public getCommunities() { + this.loading = true; + this.status = this.errorCodes.LOADING; + this.subscriberErrorMessage = ""; + + this.researchCommunities = []; + + this._communitiesService.getCommunitiesState().subscribe( + communitiesResults => { + if(!communitiesResults){ + return; + } + if(communitiesResults.length == 0) { + this.status = this.errorCodes.DONE; + return; + } + this.sort(communitiesResults); + communitiesResults.forEach((community, index) => { + let showCommunity: boolean = true; + if (community['status'] == "hidden" || community['status'] == "manager") { + showCommunity = false; + } + if (showCommunity) { + this.researchCommunities.push(community); + } + this.status = this.errorCodes.DONE; + }); + this.loading = false; + }, + error => { + this.status = this.handleError("Error getting communities", error); + this.loading = false; + } + ); + } + + private createGifs() { + this.gifs.push({ + gif: "assets/connect-assets/home/gifs/deposit.gif", + header: "Find a repository to deposit your research outcome", + text: "This is OpenAIRE’s key service for research communities, both established and emerging ones. Our service helps you reach out and engage all your researchers to practice open science out-of-the-box." + }); + this.gifs.push({ + gif: "assets/connect-assets/home/gifs/link.gif", + header: "Link your research output with your community, funding, and other research products", + text: "This is OpenAIRE’s key service for research communities, both established and emerging ones. Our service helps you reach out and engage all your researchers to practice open science out-of-the-box." + }); + this.gifs.push({ + gif: "assets/connect-assets/home/gifs/overview.gif", + header: "View community's overview at a glance", + text: "This is OpenAIRE’s key service for research communities, both established and emerging ones. Our service helps you reach out and engage all your researchers to practice open science out-of-the-box." + }); + this.gifs.push({ + gif: "assets/connect-assets/home/gifs/results.gif", + header: "Search & browse your community's research products. ", + text: "This is OpenAIRE’s key service for research communities, both established and emerging ones. Our service helps you reach out and engage all your researchers to practice open science out-of-the-box." + }); + this.gifs.push({ + gif: "assets/connect-assets/home/gifs/graph-analysis.gif", + header: "View statistics for your community's research products.", + text: "This is OpenAIRE’s key service for research communities, both established and emerging ones. Our service helps you reach out and engage all your researchers to practice open science out-of-the-box." + }); + } + + private sort(results: CommunityInfo[]) { + results.sort((left, right): number => { + if (!right.date || left.date > right.date) { + return -1; + } else if (!left.date || left.date < right.date) { + return 1; + } else { + if (left.title > right.title) { + return 1; + } else if (left.title < right.title) { + return -1; + } else { + return 0; + } + } + }) + } + + public quote(param: string): string { + return StringUtils.quote(param); + } + + public ngOnDestroy() { + if (this.piwiksub) { + this.piwiksub.unsubscribe(); + } + } + + private handleError(message: string, error): number { + var code = ""; + if (!error.status) { + var error = error.json(); + code = error.code; + } else { + code = error.status; + } + + console.error("Communities (component): " + message, error); + + return this.errorMessages.getErrorCode(code); + } +} diff --git a/src/app/home/home.module.ts b/src/app/home/home.module.ts new file mode 100644 index 0000000..13dd2e3 --- /dev/null +++ b/src/app/home/home.module.ts @@ -0,0 +1,42 @@ +import {NgModule} from '@angular/core'; +import {CommonModule} from '@angular/common'; +import {FormsModule} from '@angular/forms'; +import {RouterModule} from '@angular/router'; +import {ManageModule} from '../openaireLibrary/utils/manage/manage.module'; + +import {HomeComponent} from './home.component'; + +import {FreeGuard} from '../openaireLibrary/login/freeGuard.guard'; +import {PreviousRouteRecorder} from '../openaireLibrary/utils/piwik/previousRouteRecorder.guard'; + +import {PiwikService} from '../openaireLibrary/utils/piwik/piwik.service'; +import {ErrorMessagesModule} from '../openaireLibrary/utils/errorMessages.module'; + +import {SearchFormModule} from '../openaireLibrary/searchPages/searchUtils/searchForm.module'; +import {HelperModule} from "../openaireLibrary/utils/helper/helper.module"; +import {GifSliderModule} from "../openaireLibrary/utils/gif-slider/gif-slider.module"; +import {OtherPortalsModule} from "../openaireLibrary/sharedComponents/other-portals/other-portals.module"; +import {Schema2jsonldModule} from "../openaireLibrary/sharedComponents/schema2jsonld/schema2jsonld.module"; +import {SEOServiceModule} from "../openaireLibrary/sharedComponents/SEO/SEOService.module"; +import {BrowseCommunityModule} from "../communities/browseCommunity/browse-community.module"; +import {HomeRoutingModule} from "./home-routing.module"; + +@NgModule({ + imports: [ + CommonModule, FormsModule, RouterModule, + ManageModule, ErrorMessagesModule, + SearchFormModule, GifSliderModule, OtherPortalsModule, + HelperModule, Schema2jsonldModule, SEOServiceModule, HomeRoutingModule, BrowseCommunityModule + ], + declarations: [ + HomeComponent + ], + providers:[ + FreeGuard, PreviousRouteRecorder, + PiwikService + ], + exports: [ + HomeComponent + ] +}) +export class HomeModule { } diff --git a/static.paths.ts b/static.paths.ts new file mode 100644 index 0000000..be309ca --- /dev/null +++ b/static.paths.ts @@ -0,0 +1,15 @@ +export const ROUTES = [ + '/', + '/lazy', + '/home', + '/search/publication','/search/other','/search/project','/search/dataset','/search/dataprovider','/search/organization', + '/search/find', + '/search/person','/search/publication','/search/project','/search/dataset','/search/dataprovider','/search/organization', + '/search/find/people','/search/find/publications','/search/find/other','/search/find/projects','/search/find/datasets','/search/find/dataproviders','/search/find/organizations', + '/search/advanced/people','/search/advanced/publications','/search/advanced/other','/search/advanced/projects','/search/advanced/datasets','/search/advanced/dataproviders','/search/advanced/organizations', + '/participate/deposit-publications','/participate/deposit-datasets','/participate/deposit-publications-result','/participate/deposit-datasets-result','/participate/deposit-subject-result', + '/search/content-providers','/search/content-providers-table','/search/entity-registries','/search/entity-registries-table','/search/journals','/search/journals-table', + '/project-report','/claims','/myclaims','/participate/claim','/participate/direct-claim','/claims-project-manager', + '/test','/user-info', + '/error', '/*path' +]; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..8cd9a30 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "importHelpers": true, + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "target": "es5", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2017", + "dom" + ], + "module": "es2015", + "baseUrl": "./" + } +} \ No newline at end of file diff --git a/webpack.server.config.js b/webpack.server.config.js new file mode 100644 index 0000000..4d2b44f --- /dev/null +++ b/webpack.server.config.js @@ -0,0 +1,51 @@ +// Work around for https://github.com/angular/angular-cli/issues/7200 + +const path = require('path'); +const webpack = require('webpack'); + +module.exports = { + //mode: 'none', + entry: { + // This is our Express server for Dynamic universal + server: './server.ts', + // This is an example of Static prerendering (generative) + prerender: './prerender.ts' + }, + target: 'node', + resolve: { extensions: ['.ts', '.js'] }, + // Make sure we include all node_modules etc + externals: [/(node_modules|main\..*\.js)/,], + optimization: { + minimize: false + }, + output: { + // Puts the output at the root of the dist folder + path: path.join(__dirname, 'dist'), + filename: '[name].js' + }, + module: { + 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'), + {} + ) + ] +}