├── .gitignore ├── LICENSE ├── README.md ├── bs-config.js ├── config ├── helpers.js ├── webpack.config.common.js ├── webpack.config.dev.js └── webpack.config.prod.js ├── package.json ├── src ├── app │ ├── app-routing.module.ts │ ├── app.component.html │ ├── app.component.scss │ ├── app.component.ts │ ├── app.module.ts │ ├── modules │ │ └── menu │ │ │ ├── components │ │ │ └── menu │ │ │ │ ├── menu.component.html │ │ │ │ ├── menu.component.scss │ │ │ │ └── menu.component.ts │ │ │ ├── menu-routing.module.ts │ │ │ └── menu.module.ts │ └── shared │ │ └── components │ │ └── home │ │ ├── home.component.html │ │ ├── home.component.scss │ │ └── home.component.ts ├── assets │ └── styles.scss ├── index.html ├── main.aot.ts ├── main.ts ├── polyfills.ts └── vendor.ts ├── tsconfig.aot.json ├── tsconfig.json └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /tmp 4 | 5 | # dependencies 6 | /node_modules 7 | 8 | # IDEs and editors 9 | /.idea 10 | .project 11 | .classpath 12 | .c9/ 13 | *.launch 14 | .settings/ 15 | 16 | # IDE - VSCode 17 | .vscode/* 18 | !.vscode/settings.json 19 | !.vscode/tasks.json 20 | !.vscode/launch.json 21 | !.vscode/extensions.json 22 | 23 | # misc 24 | /.sass-cache 25 | /connect.lock 26 | /coverage/* 27 | /libpeerconnection.log 28 | npm-debug.log 29 | testem.log 30 | /typings 31 | 32 | # e2e 33 | /e2e/*.js 34 | /e2e/*.map 35 | 36 | #System Files 37 | .DS_Store 38 | Thumbs.db 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Samuel Teboul 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular 7 application with webpack 4 boilerplate 2 | 3 | This repo is a support for [this article](https://medium.freecodecamp.org/how-to-configure-webpack-4-with-angular-7-a-complete-guide-9a23c879f471) published on Medium 4 | -------------------------------------------------------------------------------- /bs-config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | server: { 5 | baseDir: './dist', 6 | middleware: { 7 | 1: require('connect-history-api-fallback')({ index: '/index.html', verbose: true }) 8 | } 9 | } 10 | }; -------------------------------------------------------------------------------- /config/helpers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | 5 | const _root = path.resolve(__dirname, '..'); 6 | 7 | function root(args) { 8 | args = Array.prototype.slice.call(arguments, 0); 9 | 10 | return path.join.apply(path, [_root].concat(args)); 11 | } 12 | 13 | exports.root = root; -------------------------------------------------------------------------------- /config/webpack.config.common.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const CleanWebpackPlugin = require('clean-webpack-plugin'); 4 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 5 | 6 | const helpers = require('./helpers'); 7 | const isDev = process.env.NODE_ENV !== 'production'; 8 | 9 | module.exports = { 10 | entry: { 11 | vendor: './src/vendor.ts', 12 | polyfills: './src/polyfills.ts', 13 | main: isDev ? './src/main.ts' : './src/main.aot.ts' 14 | }, 15 | 16 | resolve: { 17 | extensions: ['.ts', '.js', '.scss'] 18 | }, 19 | 20 | module: { 21 | rules: [ 22 | { 23 | test: /\.html$/, 24 | loader: 'html-loader' 25 | }, 26 | { 27 | test: /\.(scss|sass)$/, 28 | use: [ 29 | { loader: 'style-loader', options: { sourceMap: isDev } }, 30 | { loader: 'css-loader', options: { sourceMap: isDev } }, 31 | { loader: 'sass-loader', options: { sourceMap: isDev } } 32 | ], 33 | include: helpers.root('src', 'assets') 34 | }, 35 | { 36 | test: /\.(scss|sass)$/, 37 | use: [ 38 | 'to-string-loader', 39 | { loader: 'css-loader', options: { sourceMap: isDev } }, 40 | { loader: 'sass-loader', options: { sourceMap: isDev } } 41 | ], 42 | include: helpers.root('src', 'app') 43 | } 44 | ] 45 | }, 46 | 47 | plugins: [ 48 | new CleanWebpackPlugin( 49 | helpers.root('dist'), { root: helpers.root(), verbose: true }), 50 | 51 | new HtmlWebpackPlugin({ 52 | template: 'src/index.html' 53 | }) 54 | ] 55 | }; -------------------------------------------------------------------------------- /config/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const webpackMerge = require('webpack-merge'); 4 | 5 | const commonConfig = require('./webpack.config.common'); 6 | const helpers = require('./helpers'); 7 | 8 | module.exports = webpackMerge(commonConfig, { 9 | mode: 'development', 10 | 11 | devtool: 'cheap-module-eval-source-map', 12 | 13 | output: { 14 | path: helpers.root('dist'), 15 | publicPath: '/', 16 | filename: '[name].bundle.js', 17 | chunkFilename: '[id].chunk.js' 18 | }, 19 | 20 | optimization: { 21 | noEmitOnErrors: true 22 | }, 23 | 24 | module: { 25 | rules: [ 26 | { 27 | test: /\.ts$/, 28 | loaders: [ 29 | { 30 | loader: 'awesome-typescript-loader', 31 | options: { 32 | configFileName: helpers.root('tsconfig.json') 33 | } 34 | }, 35 | 'angular2-template-loader', 36 | 'angular-router-loader' 37 | ], 38 | exclude: [/node_modules/] 39 | } 40 | ] 41 | }, 42 | 43 | devServer: { 44 | historyApiFallback: true, 45 | stats: 'minimal' 46 | } 47 | }); -------------------------------------------------------------------------------- /config/webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const webpackMerge = require('webpack-merge'); 4 | const ngw = require('@ngtools/webpack'); 5 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); 6 | const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); 7 | const cssnano = require('cssnano'); 8 | 9 | const commonConfig = require('./webpack.config.common'); 10 | const helpers = require('./helpers'); 11 | 12 | module.exports = webpackMerge(commonConfig, { 13 | mode: 'production', 14 | 15 | output: { 16 | path: helpers.root('dist'), 17 | publicPath: '/', 18 | filename: '[hash].js', 19 | chunkFilename: '[id].[hash].chunk.js' 20 | }, 21 | 22 | optimization: { 23 | noEmitOnErrors: true, 24 | splitChunks: { 25 | chunks: 'all' 26 | }, 27 | runtimeChunk: 'single', 28 | minimizer: [ 29 | new UglifyJsPlugin({ 30 | cache: true, 31 | parallel: true 32 | }), 33 | 34 | new OptimizeCSSAssetsPlugin({ 35 | cssProcessor: cssnano, 36 | cssProcessorOptions: { 37 | discardComments: { 38 | removeAll: true 39 | } 40 | }, 41 | canPrint: false 42 | }) 43 | ] 44 | }, 45 | 46 | module: { 47 | rules: [ 48 | { 49 | test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/, 50 | loader: '@ngtools/webpack' 51 | } 52 | ] 53 | }, 54 | 55 | plugins: [ 56 | new ngw.AngularCompilerPlugin({ 57 | tsConfigPath: helpers.root('tsconfig.aot.json'), 58 | entryModule: helpers.root('src', 'app', 'app.module#AppModule') 59 | }) 60 | ] 61 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-7-webpack-4-boilerplate", 3 | "version": "1.0.0", 4 | "description": "Angular 7 application with webpack 4 boilerplate", 5 | "scripts": { 6 | "webpack-dev": "cross-env NODE_ENV=development webpack --mode development", 7 | "webpack-prod": "cross-env NODE_ENV=production webpack --mode production", 8 | "build:dev": "webpack-dev-server --inline --hot --progress --port 8080", 9 | "build:prod": "npm run build:clean && ngc && npm run webpack-prod && npm run build:clean", 10 | "build:clean": "del-cli 'src/**/*.js' 'src/**/*.js.map' 'src/**/*.ngsummary.json' 'src/**/*.metadata.json' 'src/**/**/*.ngfactory.ts' 'src/**/*.ngstyle.ts' 'src/**/*.shim.ts'", 11 | "serve": "lite-server" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/samteb/Angular-7-Webpack-4.git" 16 | }, 17 | "author": "samteb ", 18 | "license": "MIT", 19 | "homepage": "https://github.com/samteb/Angular-7-Webpack-4", 20 | "dependencies": { 21 | "@angular/animations": "~7.2", 22 | "@angular/common": "~7.2", 23 | "@angular/compiler": "~7.2", 24 | "@angular/compiler-cli": "~7.2", 25 | "@angular/core": "~7.2", 26 | "@angular/forms": "~7.2", 27 | "@angular/http": "~7.2", 28 | "@angular/platform-browser": "~7.2", 29 | "@angular/platform-browser-dynamic": "~7.2", 30 | "@angular/platform-server": "~7.2", 31 | "@angular/router": "~7.2", 32 | "@angular/upgrade": "~7.2", 33 | "core-js": "~2.6", 34 | "rxjs": "~6.4", 35 | "zone.js": "~0.8" 36 | }, 37 | "devDependencies": { 38 | "@ngtools/webpack": "~7.3", 39 | "@types/core-js": "~2.5", 40 | "@types/node": "~10.12", 41 | "angular-router-loader": "~0.8", 42 | "angular2-template-loader": "~0.6", 43 | "awesome-typescript-loader": "~5.2", 44 | "babel-core": "~6.26", 45 | "babel-loader": "~7.1", 46 | "babel-preset-env": "~1.7", 47 | "clean-webpack-plugin": "~0.1", 48 | "cross-env": "~5.2", 49 | "css-loader": "~1.0", 50 | "cssnano": "~4.1", 51 | "del-cli": "~1.1", 52 | "html-loader": "~0.5", 53 | "html-webpack-plugin": "~3.2", 54 | "lite-server": "~2.4", 55 | "node-sass": "~4.12", 56 | "optimize-css-assets-webpack-plugin": "~5.0", 57 | "sass-loader": "~7.1", 58 | "style-loader": "~0.23", 59 | "to-string-loader": "~1.1", 60 | "typescript": "~3.1", 61 | "uglifyjs-webpack-plugin": "~2.0", 62 | "webpack": "~4.29", 63 | "webpack-cli": "~3.2", 64 | "webpack-dev-server": "^3.1.14", 65 | "webpack-merge": "~4.2" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | 4 | import { HomeComponent } from './shared/components/home/home.component'; 5 | 6 | const appRoutes: Routes = [ 7 | { path: '', component: HomeComponent }, 8 | { path: 'menu', loadChildren: './modules/menu/menu.module#MenuModule' } 9 | ]; 10 | 11 | @NgModule({ 12 | imports: [ 13 | RouterModule.forRoot(appRoutes) 14 | ], 15 | exports: [ 16 | RouterModule 17 | ] 18 | }) 19 | 20 | export class AppRoutingModule {} -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 |

{{name}}

2 |
3 | Home | Menu 4 |
5 | -------------------------------------------------------------------------------- /src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | h1 { 2 | color: darkblue; 3 | } 4 | 5 | a { 6 | font-size: 20px; 7 | } -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.scss'] 7 | }) 8 | 9 | export class AppComponent { 10 | name = 'Angular 7 & Webpack 4'; 11 | } -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | 4 | import { AppRoutingModule } from './app-routing.module'; 5 | 6 | import { AppComponent } from './app.component'; 7 | import { HomeComponent } from './shared/components/home/home.component'; 8 | 9 | import '../assets/styles'; 10 | 11 | @NgModule({ 12 | declarations: [ 13 | AppComponent, 14 | HomeComponent 15 | ], 16 | imports: [ 17 | BrowserModule, 18 | AppRoutingModule 19 | ], 20 | providers: [], 21 | bootstrap: [ 22 | AppComponent 23 | ] 24 | }) 25 | 26 | export class AppModule {} -------------------------------------------------------------------------------- /src/app/modules/menu/components/menu/menu.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Menu Page

3 |
-------------------------------------------------------------------------------- /src/app/modules/menu/components/menu/menu.component.scss: -------------------------------------------------------------------------------- 1 | div { 2 | h1 { 3 | color: green; 4 | } 5 | } -------------------------------------------------------------------------------- /src/app/modules/menu/components/menu/menu.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'menu-page', 5 | templateUrl: './menu.component.html', 6 | styleUrls: ['./menu.component.scss'] 7 | }) 8 | 9 | export class MenuComponent {} -------------------------------------------------------------------------------- /src/app/modules/menu/menu-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | 4 | import { MenuComponent } from './components/menu/menu.component'; 5 | 6 | const appRoutes: Routes = [ 7 | { path: '', component: MenuComponent } 8 | ]; 9 | 10 | @NgModule({ 11 | imports: [ 12 | RouterModule.forChild(appRoutes) 13 | ], 14 | exports: [ 15 | RouterModule 16 | ] 17 | }) 18 | 19 | 20 | export class MenuRoutingModule {} -------------------------------------------------------------------------------- /src/app/modules/menu/menu.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | import { MenuRoutingModule } from './menu-routing.module'; 5 | import { MenuComponent } from './components/menu/menu.component'; 6 | 7 | @NgModule({ 8 | declarations: [ 9 | MenuComponent 10 | ], 11 | imports: [ 12 | CommonModule, 13 | MenuRoutingModule 14 | ], 15 | providers: [] 16 | }) 17 | 18 | export class MenuModule {} -------------------------------------------------------------------------------- /src/app/shared/components/home/home.component.html: -------------------------------------------------------------------------------- 1 |

Home Page

-------------------------------------------------------------------------------- /src/app/shared/components/home/home.component.scss: -------------------------------------------------------------------------------- 1 | h1 { 2 | color: red; 3 | } -------------------------------------------------------------------------------- /src/app/shared/components/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'home-page', 5 | templateUrl: './home.component.html', 6 | styleUrls: ['./home.component.scss'] 7 | }) 8 | 9 | export class HomeComponent {} -------------------------------------------------------------------------------- /src/assets/styles.scss: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: cornflowerblue; 3 | } -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Restaurant Menu 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/main.aot.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowser } from '@angular/platform-browser'; 3 | 4 | import { AppModuleNgFactory } from './app/app.module.ngfactory'; 5 | 6 | enableProdMode(); 7 | 8 | platformBrowser().bootstrapModuleFactory(AppModuleNgFactory); -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 2 | import { AppModule } from './app/app.module'; 3 | 4 | platformBrowserDynamic().bootstrapModule(AppModule); -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | import 'core-js/es6'; 2 | import 'core-js/es7/reflect'; 3 | require('zone.js/dist/zone'); 4 | 5 | if (process.env.ENV === 'production') { 6 | // Production 7 | } else { 8 | // Development and test 9 | Error['stackTraceLimit'] = Infinity; 10 | require('zone.js/dist/long-stack-trace-zone'); 11 | } -------------------------------------------------------------------------------- /src/vendor.ts: -------------------------------------------------------------------------------- 1 | // Angular 2 | import '@angular/animations'; 3 | import '@angular/common'; 4 | import '@angular/core'; 5 | import '@angular/forms'; 6 | import '@angular/http'; 7 | import '@angular/router'; 8 | 9 | // RxJS 10 | import 'rxjs'; -------------------------------------------------------------------------------- /tsconfig.aot.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "noImplicitAny": true, 10 | "suppressImplicitAnyIndexErrors": true, 11 | "lib": ["es6", "dom"], 12 | "typeRoots": ["node_modules/@types"] 13 | }, 14 | "exclude": [ 15 | "node_modules", 16 | "src/main.ts" 17 | ] 18 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "noImplicitAny": true, 10 | "suppressImplicitAnyIndexErrors": true, 11 | "lib": ["es6", "dom"], 12 | "typeRoots": ["node_modules/@types"] 13 | }, 14 | "exclude": [ 15 | "node_modules", 16 | "src/main.aot.ts" 17 | ] 18 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const environment = (process.env.NODE_ENV || 'development').trim(); 4 | 5 | if (environment === 'development') { 6 | module.exports = require('./config/webpack.config.dev'); 7 | } else { 8 | module.exports = require('./config/webpack.config.prod'); 9 | } --------------------------------------------------------------------------------