├── .gitignore ├── README.md ├── config ├── helpers.js ├── polyfills.ts ├── vendor.ts ├── webpack.dev-with-dll.js ├── webpack.dev.js └── webpack.dll.js ├── package.json ├── src ├── app.component.ts ├── app.module.ts ├── app.routing.ts ├── hello │ ├── hello.component.ts │ ├── hello.css │ └── hello.html ├── index.html ├── main.ts └── utils │ └── hmr.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | src/**/*.js 4 | src/**/*.map 5 | npm-debug.log -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Webpacked Angular with a side of Dll (+ HMR freebie) 2 | 3 | Basic project showing usage of [`webpack.DllPlugin`][1] with Angular 2.2.1 to minimize build times during development. Also implements HMR using great work from [angular2-hmr][2] and [angular2-hmr-loader][3]. 4 | 5 | To install, clone this repo and: 6 | ``` 7 | npm install 8 | npm run dev:dll 9 | ``` 10 | Then, go to [http://localhost:8080/dist](http://localhost:8080/dist) to say hello. 11 | 12 | Some references: 13 | - [Optimizing Webpack build times and improving caching with DLL bundles - Rob Knight][4] 14 | - [Angular 2 Hot Loading with @ngrx/store and Webpack - Tero Parviainen][5] 15 | - [teropa/ngrx-hotload-rc5][6] 16 | 17 | [1]: https://webpack.github.io/docs/list-of-plugins.html#dllplugin 18 | [2]: https://github.com/AngularClass/angular2-hmr 19 | [3]: https://github.com/AngularClass/angular2-hmr-loader 20 | [4]: https://robertknight.github.io/posts/webpack-dll-plugins/ 21 | [5]: http://teropa.info/blog/2016/08/08/angular-2-hot-loading-with-ngrx-store-and-webpack.html 22 | [6]: https://github.com/teropa/ngrx-hotload-rc5 23 | -------------------------------------------------------------------------------- /config/helpers.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var _root = path.resolve(__dirname, '..'); 3 | function root(args) { 4 | args = Array.prototype.slice.call(arguments, 0); 5 | return path.join.apply(path, [_root].concat(args)); 6 | } 7 | exports.root = root; -------------------------------------------------------------------------------- /config/polyfills.ts: -------------------------------------------------------------------------------- 1 | import 'core-js/es6'; 2 | import 'core-js/es7/reflect'; 3 | require('zone.js/dist/zone'); 4 | if (process.env.ENV === 'production') { 5 | // Production 6 | } else { 7 | // Development 8 | Error['stackTraceLimit'] = Infinity; 9 | require('zone.js/dist/long-stack-trace-zone'); 10 | } -------------------------------------------------------------------------------- /config/vendor.ts: -------------------------------------------------------------------------------- 1 | //Angular 2 2 | import '@angular/platform-browser'; 3 | import '@angular/platform-browser-dynamic'; 4 | import '@angular/core'; 5 | import '@angular/common'; 6 | import '@angular/http'; 7 | import '@angular/router'; 8 | import '@angular/forms'; 9 | // RxJS 10 | import 'rxjs'; 11 | -------------------------------------------------------------------------------- /config/webpack.dev-with-dll.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | var AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin'); 4 | var helpers = require('./helpers'); 5 | 6 | module.exports = { 7 | entry: [ 8 | './config/polyfills.ts', 9 | './src/main.ts' 10 | ], 11 | 12 | output: { 13 | path: helpers.root('dist'), 14 | publicPath: 'http://localhost:8080/', 15 | filename: 'bundle.js' 16 | }, 17 | 18 | resolve: { 19 | // resolve module file requests by looking for explicit extensions 20 | // or look for matching files with .js or .ts extensions 21 | extensions: ['*', '.js', '.ts'] 22 | }, 23 | 24 | module: { 25 | loaders: [ 26 | { 27 | test: /\.ts$/, 28 | loaders: ['awesome-typescript-loader', '@angularclass/hmr-loader', 'angular2-template-loader'], 29 | }, 30 | { 31 | test: /\.html$/, 32 | loader: 'raw-loader' 33 | }, 34 | // handle component-scoped styles specified with styleUrls 35 | { 36 | test: /\.css$/, 37 | include: helpers.root('src'), 38 | loader: 'raw-loader' 39 | } 40 | ] 41 | }, 42 | 43 | plugins: [ 44 | new webpack.DllReferencePlugin({ 45 | context: '.', 46 | manifest: require(helpers.root('dist', 'vendor-manifest.json')) 47 | }), 48 | new webpack.DllReferencePlugin({ 49 | context: '.', 50 | manifest: require(helpers.root('dist', 'polyfills-manifest.json')) 51 | }), 52 | new HtmlWebpackPlugin({ 53 | template: 'src/index.html', 54 | filename: 'dist/index.html' 55 | }), 56 | new AddAssetHtmlPlugin([ 57 | { filepath: 'dist/polyfills.dll.js', includeSourcemap: false }, 58 | { filepath: 'dist/vendor.dll.js', includeSourcemap: false } 59 | ]) 60 | ], 61 | 62 | devServer: { 63 | host: '0.0.0.0', 64 | port: 8080 65 | } 66 | }; 67 | -------------------------------------------------------------------------------- /config/webpack.dev.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | var helpers = require('./helpers'); 4 | 5 | module.exports = { 6 | entry: { 7 | 'app': ['./config/polyfills.ts', './src/main.ts'] 8 | }, 9 | 10 | output: { 11 | path: helpers.root('dist'), 12 | publicPath: '/', 13 | filename: 'bundle.js' 14 | }, 15 | 16 | resolve: { 17 | // resolve module file requests by looking for explicit extensions 18 | // or look for matching files with .js or .ts extensions 19 | extensions: ['*', '.js', '.ts'] 20 | }, 21 | 22 | module: { 23 | loaders: [ 24 | { 25 | test: /\.ts$/, 26 | loaders: ['awesome-typescript-loader', 'angular2-template-loader'], 27 | }, 28 | { 29 | test: /\.html$/, 30 | loader: 'raw-loader' 31 | }, 32 | // handle component-scoped styles specified with styleUrls 33 | { 34 | test: /\.css$/, 35 | include: helpers.root('src'), 36 | loader: 'raw-loader' 37 | } 38 | ] 39 | }, 40 | 41 | plugins: [ 42 | new HtmlWebpackPlugin({ 43 | template: 'src/index.html', 44 | filename: 'dist/index.html' 45 | }) 46 | ], 47 | 48 | devServer: { 49 | contentBase: 'dist/', 50 | host: '0.0.0.0', 51 | inline: true, 52 | port: 8080 53 | } 54 | }; 55 | -------------------------------------------------------------------------------- /config/webpack.dll.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | 3 | module.exports = { 4 | entry: { 5 | 'polyfills': [ './config/polyfills.ts' ], 6 | 'vendor': [ './config/vendor.ts' ] 7 | }, 8 | 9 | output: { 10 | filename: '[name].dll.js', 11 | path: 'dist/', 12 | 13 | // The name of the global variable which the library's 14 | // require() function will be assigned to 15 | library: '[name]', 16 | }, 17 | 18 | plugins: [ 19 | new webpack.DllPlugin({ 20 | // The path to the manifest file which maps between 21 | // modules included in a bundle and the internal IDs 22 | // within that bundle 23 | path: 'dist/[name]-manifest.json', 24 | // The name of the global variable which the library's 25 | // require function has been assigned to. This must match the 26 | // output.library option above 27 | name: '[name]' 28 | }), 29 | ], 30 | }; 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpacked-angular-with-dll", 3 | "version": "1.0.2", 4 | "description": "Sample demonstrating usage of webpack and dllplugin to bundle an angular project.", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "npm run clean && webpack --config config/webpack.dev.js --progress --profile --bail", 8 | "build:dll": "webpack --config config/webpack.dll.js --progress --profile --bail", 9 | "dev": "webpack-dev-server --config config/webpack.dev.js", 10 | "hotdll": "webpack-dev-server --config config/webpack.dev-with-dll.js --hot --inline", 11 | "dev:dll": "npm run clean && npm run build:dll && npm run hotdll", 12 | "clean": "npm run clean:dist && npm run clean:tsc", 13 | "clean:dist": "rimraf dist", 14 | "clean:tsc": "rimraf src/**/*.js && rimraf src/**/*.map" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/radusuciu/webpacked-angular-with-dll.git" 19 | }, 20 | "author": "Radu Suciu", 21 | "license": "ISC", 22 | "bugs": { 23 | "url": "https://github.com/radusuciu/webpacked-angular-with-dll/issues" 24 | }, 25 | "homepage": "https://github.com/radusuciu/webpacked-angular-with-dll#readme", 26 | "dependencies": { 27 | "@angular/common": "2.2.1", 28 | "@angular/compiler": "2.2.1", 29 | "@angular/core": "2.2.1", 30 | "@angular/forms": "2.2.1", 31 | "@angular/http": "2.2.1", 32 | "@angular/platform-browser": "2.2.1", 33 | "@angular/platform-browser-dynamic": "2.2.1", 34 | "@angular/router": "3.2.1", 35 | "core-js": "2.4.1", 36 | "rxjs": "5.0.0-beta.12", 37 | "zone.js": "0.6.25" 38 | }, 39 | "devDependencies": { 40 | "@angularclass/hmr": "1.2.2", 41 | "@angularclass/hmr-loader": "3.0.2", 42 | "@types/core-js": "0.9.34", 43 | "@types/node": "6.0.49", 44 | "add-asset-html-webpack-plugin": "1.0.2", 45 | "angular2-template-loader": "0.6.0", 46 | "awesome-typescript-loader": "2.2.4", 47 | "html-webpack-plugin": "2.24.1", 48 | "raw-loader": "0.5.1", 49 | "rimraf": "2.5.4", 50 | "typescript": "2.0.10", 51 | "webpack": "2.1.0-beta.27", 52 | "webpack-dev-server": "2.1.0-beta.11" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app', 5 | template: '' 6 | }) 7 | export class AppComponent {} -------------------------------------------------------------------------------- /src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule, ApplicationRef } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { RouterModule } from '@angular/router'; 4 | import { FormsModule } from '@angular/forms'; 5 | import { HttpModule } from '@angular/http'; 6 | 7 | import { HMR } from './utils/hmr'; 8 | 9 | import { AppComponent } from './app.component'; 10 | import { HelloComponent } from './hello/hello.component'; 11 | 12 | import { routing } from './app.routing'; 13 | 14 | @NgModule({ 15 | imports: [ 16 | BrowserModule, 17 | FormsModule, 18 | HttpModule, 19 | RouterModule, 20 | routing 21 | ], 22 | declarations: [ 23 | AppComponent, HelloComponent 24 | ], 25 | bootstrap: [ AppComponent ] 26 | }) 27 | export class AppModule extends HMR { 28 | constructor(public appRef: ApplicationRef) { 29 | super(appRef); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/app.routing.ts: -------------------------------------------------------------------------------- 1 | import { Routes, RouterModule } from '@angular/router'; 2 | import { HelloComponent } from './hello/hello.component'; 3 | 4 | const routes: Routes = [ 5 | { path: '**', component: HelloComponent } 6 | ]; 7 | 8 | export const routing = RouterModule.forRoot(routes); -------------------------------------------------------------------------------- /src/hello/hello.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | templateUrl: 'hello.html', 5 | styleUrls: [ 'hello.css' ] 6 | }) 7 | export class HelloComponent {} -------------------------------------------------------------------------------- /src/hello/hello.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radusuciu/webpacked-angular-with-dll/5e19477834de2d81925d5b40ba92e08a9447d780/src/hello/hello.css -------------------------------------------------------------------------------- /src/hello/hello.html: -------------------------------------------------------------------------------- 1 |

Hello, world.

2 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Webpacked Angular with a side of Dll 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 2 | import { AppModule } from './app.module'; 3 | import { enableProdMode } from '@angular/core'; 4 | 5 | if (process.env.ENV === 'production') { 6 | enableProdMode(); 7 | } 8 | 9 | platformBrowserDynamic().bootstrapModule(AppModule); -------------------------------------------------------------------------------- /src/utils/hmr.ts: -------------------------------------------------------------------------------- 1 | import { ApplicationRef } from '@angular/core'; 2 | import { removeNgStyles, createNewHosts } from '@angularclass/hmr'; 3 | 4 | 5 | export class HMR { 6 | constructor(public appRef: ApplicationRef) {} 7 | 8 | hmrOnInit(store) { 9 | if (!store) return; 10 | } 11 | 12 | hmrOnDestroy(store) { 13 | var cmpLocation = this.appRef.components.map(cmp => cmp.location.nativeElement); 14 | // recreate elements 15 | store.disposeOldHosts = createNewHosts(cmpLocation); 16 | // remove styles 17 | removeNgStyles(); 18 | } 19 | 20 | hmrAfterDestroy(store) { 21 | // display new elements 22 | store.disposeOldHosts(); 23 | delete store.disposeOldHosts; 24 | // anything you need done the component is removed 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "removeComments": false, 10 | "noImplicitAny": false, 11 | "types": [ "core-js", "node" ] 12 | }, 13 | "awesomeTypescriptLoaderOptions": { 14 | // Allows other loaders to be chained to awesome-typescript-loader 15 | "useWebpackText": true 16 | }, 17 | "exclude": [ "node_modules", "config", "dist" ] 18 | } --------------------------------------------------------------------------------