diff --git a/templates/AngularSpa/ClientApp/app/app.module.browser.ts b/templates/AngularSpa/ClientApp/app/app.module.browser.ts index e3393ce..7e71ca9 100644 --- a/templates/AngularSpa/ClientApp/app/app.module.browser.ts +++ b/templates/AngularSpa/ClientApp/app/app.module.browser.ts @@ -10,8 +10,12 @@ import { AppComponent } from './components/app/app.component'; AppModuleShared ], providers: [ - { provide: 'ORIGIN_URL', useValue: location.origin } + { provide: 'ORIGIN_URL', useFactory: getOriginUrl } ] }) export class AppModule { } + +export function getOriginUrl() { + return location.origin; +} diff --git a/templates/AngularSpa/ClientApp/boot-client.ts b/templates/AngularSpa/ClientApp/boot.client.ts similarity index 100% rename from templates/AngularSpa/ClientApp/boot-client.ts rename to templates/AngularSpa/ClientApp/boot.client.ts diff --git a/templates/AngularSpa/ClientApp/boot-server.ts b/templates/AngularSpa/ClientApp/boot.server.ts similarity index 100% rename from templates/AngularSpa/ClientApp/boot-server.ts rename to templates/AngularSpa/ClientApp/boot.server.ts diff --git a/templates/AngularSpa/npm-shrinkwrap.json b/templates/AngularSpa/npm-shrinkwrap.json index 6b2c236..f4f3ada 100644 --- a/templates/AngularSpa/npm-shrinkwrap.json +++ b/templates/AngularSpa/npm-shrinkwrap.json @@ -17,6 +17,18 @@ "from": "@angular/compiler@4.2.5", "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-4.2.5.tgz" }, + "@angular/compiler-cli": { + "version": "4.2.5", + "from": "@angular/compiler-cli@latest", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-4.2.5.tgz", + "dependencies": { + "minimist": { + "version": "1.2.0", + "from": "minimist@>=1.2.0 <2.0.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz" + } + } + }, "@angular/core": { "version": "4.2.5", "from": "@angular/core@4.2.5", @@ -52,6 +64,23 @@ "from": "@angular/router@4.2.5", "resolved": "https://registry.npmjs.org/@angular/router/-/router-4.2.5.tgz" }, + "@angular/tsc-wrapped": { + "version": "4.2.5", + "from": "@angular/tsc-wrapped@4.2.5", + "resolved": "https://registry.npmjs.org/@angular/tsc-wrapped/-/tsc-wrapped-4.2.5.tgz" + }, + "@ngtools/webpack": { + "version": "1.5.0", + "from": "@ngtools/webpack@latest", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-1.5.0.tgz", + "dependencies": { + "loader-utils": { + "version": "1.1.0", + "from": "loader-utils@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz" + } + } + }, "@types/chai": { "version": "4.0.1", "from": "@types/chai@4.0.1", @@ -1942,6 +1971,11 @@ "from": "macaddress@>=0.2.8 <0.3.0", "resolved": "https://registry.npmjs.org/macaddress/-/macaddress-0.2.8.tgz" }, + "magic-string": { + "version": "0.19.1", + "from": "magic-string@>=0.19.0 <0.20.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.19.1.tgz" + }, "map-cache": { "version": "0.2.2", "from": "map-cache@>=0.2.2 <0.3.0", @@ -3288,6 +3322,18 @@ "from": "to-string-loader@1.1.5", "resolved": "https://registry.npmjs.org/to-string-loader/-/to-string-loader-1.1.5.tgz" }, + "tsickle": { + "version": "0.21.6", + "from": "tsickle@>=0.21.0 <0.22.0", + "resolved": "https://registry.npmjs.org/tsickle/-/tsickle-0.21.6.tgz", + "dependencies": { + "minimist": { + "version": "1.2.0", + "from": "minimist@^1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz" + } + } + }, "tslib": { "version": "1.7.1", "from": "tslib@>=1.7.1 <2.0.0", @@ -3456,6 +3502,11 @@ "from": "vendors@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.1.tgz" }, + "vlq": { + "version": "0.2.2", + "from": "vlq@>=0.2.1 <0.3.0", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.2.tgz" + }, "vm-browserify": { "version": "0.0.4", "from": "vm-browserify@0.0.4", diff --git a/templates/AngularSpa/package.json b/templates/AngularSpa/package.json index 9452382..58494ec 100644 --- a/templates/AngularSpa/package.json +++ b/templates/AngularSpa/package.json @@ -9,6 +9,7 @@ "@angular/animations": "4.2.5", "@angular/common": "4.2.5", "@angular/compiler": "4.2.5", + "@angular/compiler-cli": "4.2.5", "@angular/core": "4.2.5", "@angular/forms": "4.2.5", "@angular/http": "4.2.5", @@ -16,6 +17,7 @@ "@angular/platform-browser-dynamic": "4.2.5", "@angular/platform-server": "4.2.5", "@angular/router": "4.2.5", + "@ngtools/webpack": "1.5.0", "@types/node": "8.0.8", "angular2-template-loader": "0.6.2", "aspnet-prerendering": "^2.0.5", diff --git a/templates/AngularSpa/webpack.config.js b/templates/AngularSpa/webpack.config.js index 8c1969d..69a2e30 100644 --- a/templates/AngularSpa/webpack.config.js +++ b/templates/AngularSpa/webpack.config.js @@ -1,6 +1,7 @@ const path = require('path'); const webpack = require('webpack'); const merge = require('webpack-merge'); +const AotPlugin = require('@ngtools/webpack').AotPlugin; const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin; module.exports = (env) => { @@ -16,7 +17,7 @@ module.exports = (env) => { }, module: { rules: [ - { test: /\.ts$/, include: /ClientApp/, use: ['awesome-typescript-loader?silent=true', 'angular2-template-loader'] }, + { test: /\.ts$/, include: /ClientApp/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader'] : '@ngtools/webpack' }, { test: /\.html$/, use: 'html-loader?minimize=false' }, { test: /\.css$/, use: [ 'to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] }, { test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' } @@ -28,7 +29,7 @@ module.exports = (env) => { // Configuration for client-side bundle suitable for running in browsers const clientBundleOutputDir = './wwwroot/dist'; const clientBundleConfig = merge(sharedConfig, { - entry: { 'main-client': './ClientApp/boot-client.ts' }, + entry: { 'main-client': './ClientApp/boot.client.ts' }, output: { path: path.join(__dirname, clientBundleOutputDir) }, plugins: [ new webpack.DllReferencePlugin({ @@ -43,14 +44,19 @@ module.exports = (env) => { }) ] : [ // Plugins that apply in production builds only - new webpack.optimize.UglifyJsPlugin() + new webpack.optimize.UglifyJsPlugin(), + new AotPlugin({ + tsConfigPath: './tsconfig.json', + entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'), + exclude: ['./**/*.server.ts'] + }) ]) }); // Configuration for server-side (prerendering) bundle suitable for running in Node const serverBundleConfig = merge(sharedConfig, { resolve: { mainFields: ['main'] }, - entry: { 'main-server': './ClientApp/boot-server.ts' }, + entry: { 'main-server': './ClientApp/boot.server.ts' }, plugins: [ new webpack.DllReferencePlugin({ context: __dirname, @@ -58,7 +64,14 @@ module.exports = (env) => { sourceType: 'commonjs2', name: './vendor' }) - ], + ].concat(isDevBuild ? [] : [ + // Plugins that apply in production builds only + new AotPlugin({ + tsConfigPath: './tsconfig.json', + entryModule: path.join(__dirname, 'ClientApp/app/app.module.server#AppModule'), + exclude: ['./**/*.client.ts'] + }) + ]), output: { libraryTarget: 'commonjs', path: path.join(__dirname, './ClientApp/dist') diff --git a/templates/AngularSpa/webpack.config.vendor.js b/templates/AngularSpa/webpack.config.vendor.js index 7b0c301..ed7fa93 100644 --- a/templates/AngularSpa/webpack.config.vendor.js +++ b/templates/AngularSpa/webpack.config.vendor.js @@ -2,6 +2,27 @@ const path = require('path'); const webpack = require('webpack'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); const merge = require('webpack-merge'); +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-promise', + 'es6-shim', + 'event-source-polyfill', + 'jquery', +]; +const allModules = treeShakableModules.concat(nonTreeShakableModules); module.exports = (env) => { const extractCSS = new ExtractTextPlugin('vendor.css'); @@ -14,26 +35,6 @@ module.exports = (env) => { { test: /\.(png|woff|woff2|eot|ttf|svg)(\?|$)/, use: 'url-loader?limit=100000' } ] }, - entry: { - vendor: [ - '@angular/animations', - '@angular/common', - '@angular/compiler', - '@angular/core', - '@angular/forms', - '@angular/http', - '@angular/platform-browser', - '@angular/platform-browser-dynamic', - '@angular/router', - 'bootstrap', - 'bootstrap/dist/css/bootstrap.css', - 'es6-shim', - 'es6-promise', - 'event-source-polyfill', - 'jquery', - 'zone.js', - ] - }, output: { publicPath: '/dist/', filename: '[name].js', @@ -48,6 +49,11 @@ module.exports = (env) => { }; 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: [ @@ -68,6 +74,7 @@ module.exports = (env) => { const serverBundleConfig = merge(sharedConfig, { target: 'node', resolve: { mainFields: ['main'] }, + entry: { vendor: allModules.concat(['aspnet-prerendering']) }, output: { path: path.join(__dirname, 'ClientApp', 'dist'), libraryTarget: 'commonjs2', @@ -75,7 +82,6 @@ module.exports = (env) => { module: { rules: [ { test: /\.css(\?|$)/, use: ['to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] } ] }, - entry: { vendor: ['aspnet-prerendering'] }, plugins: [ new webpack.DllPlugin({ path: path.join(__dirname, 'ClientApp', 'dist', '[name]-manifest.json'),