How to bundle an Angular app for production

I would like to track and update in this thread the latest best (and hopefully the simplest) method to bundle Angular (version 2, 4, ...) for production on a live web server.

Please include the Angular version within answers so we can track better when it moves to later releases.


2.x, 4.x, 5.x, 6.x (TypeScript) with Angular CLI

OneTime Setup

  • npm install -g @angular/cli
  • ng new projectFolder creates a new application
  • Bundling Step

  • ng build --prod (run in command line when directory is projectFolder )

    flag prod bundle for production (see the Angular documentation for the list of option included with the production flag).

  • Compress using Brotli compression the resources using the following command

    for i in dist/*; do brotli $i; done

  • bundles are generated by default to projectFolder/dist(/$projectFolder for 6)

    Output

    Sizes with Angular 6.0.1 with CLI 6.0.1

  • dist/main.[hash].bundle.js Your application bundled [ size: 151 KB for new Angular CLI application empty, 37 KB compressed].
  • dist/polyfill.[hash].bundle.js the polyfill dependencies (@angular, RxJS...) bundled [ size: 58 KB for new Angular CLI application empty, 17 KB compressed].
  • dist/index.html entry point of your application.
  • dist/inline.[hash].bundle.js webpack loader
  • dist/style.[hash].bundle.css the style definitions
  • dist/assets resources copied from the Angular CLI assets configuration
  • Deployment

    You can get a preview of your application using the ng serve --prod command that starts a local HTTP server such that the application with production files is accessible using http://localhost:4200.

    For a production usage, you have to deploy all the files from the dist folder in the HTTP server of your choice.


    2.0.1 Final using Gulp (TypeScript - Target: ES5)


    OneTime Setup

  • npm install (run in cmd when direcory is projectFolder)
  • Bundling Steps

  • npm run bundle (run in cmd when direcory is projectFolder)

    bundles are generated to projectFolder / bundles /

  • Output

  • bundles/dependencies.bundle.js [ size: ~ 1 MB (as small as possible) ]
  • contains rxjs and angular dependencies, not the whole frameworks
  • bundles/app.bundle.js [ size: depends on your project , mine is ~ 0.5 MB ]
  • contains your project
  • File Structure

  • projectFolder / app / (all components, directives, templates, etc)
  • projectFolder / gulpfile.js
  • var gulp = require('gulp'),
      tsc = require('gulp-typescript'),
      Builder = require('systemjs-builder'),
      inlineNg2Template = require('gulp-inline-ng2-template');
    
    gulp.task('bundle', ['bundle-app', 'bundle-dependencies'], function(){});
    
    gulp.task('inline-templates', function () {
      return gulp.src('app/**/*.ts')
        .pipe(inlineNg2Template({ useRelativePaths: true, indent: 0, removeLineBreaks: true}))
        .pipe(tsc({
          "target": "ES5",
          "module": "system",
          "moduleResolution": "node",
          "sourceMap": true,
          "emitDecoratorMetadata": true,
          "experimentalDecorators": true,
          "removeComments": true,
          "noImplicitAny": false
        }))
        .pipe(gulp.dest('dist/app'));
    });
    
    gulp.task('bundle-app', ['inline-templates'], function() {
      // optional constructor options
      // sets the baseURL and loads the configuration file
      var builder = new Builder('', 'dist-systemjs.config.js');
    
      return builder
        .bundle('dist/app/**/* - [@angular/**/*.js] - [rxjs/**/*.js]', 'bundles/app.bundle.js', { minify: true})
        .then(function() {
          console.log('Build complete');
        })
        .catch(function(err) {
          console.log('Build error');
          console.log(err);
        });
    });
    
    gulp.task('bundle-dependencies', ['inline-templates'], function() {
      // optional constructor options
      // sets the baseURL and loads the configuration file
      var builder = new Builder('', 'dist-systemjs.config.js');
    
      return builder
        .bundle('dist/app/**/*.js - [dist/app/**/*.js]', 'bundles/dependencies.bundle.js', { minify: true})
        .then(function() {
          console.log('Build complete');
        })
        .catch(function(err) {
          console.log('Build error');
          console.log(err);
        });
    });
    
  • projectFolder / package.json (same as Quickstart guide, just shown devDependencies and npm-scripts required to bundle)
  • {
      "name": "angular2-quickstart",
      "version": "1.0.0",
      "scripts": {
        ***
         "gulp": "gulp",
         "rimraf": "rimraf",
         "bundle": "gulp bundle",
         "postbundle": "rimraf dist"
      },
      "license": "ISC",
      "dependencies": {
        ***
      },
      "devDependencies": {
        "rimraf": "^2.5.2",
        "gulp": "^3.9.1",
        "gulp-typescript": "2.13.6",
        "gulp-inline-ng2-template": "2.0.1",
        "systemjs-builder": "^0.15.16"
      }
    }
    
  • projectFolder / systemjs.config.js (same as Quickstart guide, not available there anymore)
  • (function(global) {
    
      // map tells the System loader where to look for things
      var map = {
        'app':                        'app',
        'rxjs':                       'node_modules/rxjs',
        'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
        '@angular':                   'node_modules/@angular'
      };
    
      // packages tells the System loader how to load when no filename and/or no extension
      var packages = {
        'app':                        { main: 'app/boot.js',  defaultExtension: 'js' },
        'rxjs':                       { defaultExtension: 'js' },
        'angular2-in-memory-web-api': { defaultExtension: 'js' }
      };
    
      var packageNames = [
        '@angular/common',
        '@angular/compiler',
        '@angular/core',
        '@angular/forms',
        '@angular/http',
        '@angular/platform-browser',
        '@angular/platform-browser-dynamic',
        '@angular/router',
        '@angular/router-deprecated',
        '@angular/testing',
        '@angular/upgrade',
      ];
    
      // add package entries for angular packages in the form '@angular/common': { main: 'index.js', defaultExtension: 'js' }
      packageNames.forEach(function(pkgName) {
        packages[pkgName] = { main: 'index.js', defaultExtension: 'js' };
      });
    
      var config = {
        map: map,
        packages: packages
      };
    
      // filterSystemConfig - index.asp's chance to modify config before we register it.
      if (global.filterSystemConfig) { global.filterSystemConfig(config); }
    
      System.config(config);
    
    })(this);
    
  • projetcFolder / dist-systemjs.config.js (just shown the difference with systemjs.config.json)
  • var map = {
        'app':                        'dist/app',
      };
    
  • projectFolder / index.html (production) - The order of the script tags is critical. Placing the dist-systemjs.config.js tag after the bundle tags would still allow the program to run but the dependency bundle would be ignored and dependencies would be loaded from the node_modules folder.
  • <!doctype html>
    <html lang="en">
    <head>
      <meta charset="utf-8"/>
      <meta name="viewport" content="width=device-width, initial-scale=1"/>
      <base href="/"/>
      <title>Angular</title>
      <link rel="stylesheet" type="text/css" href="style.css"/>
    </head>
    <body>
    
    <my-app>
      loading...
    </my-app>
    
    <!-- Polyfill(s) for older browsers -->
    <script src="node_modules/core-js/client/shim.min.js"></script>
    
    <script src="node_modules/zone.js/dist/zone.min.js"></script>
    <script src="node_modules/reflect-metadata/Reflect.js"></script>
    <script src="node_modules/systemjs/dist/system.js"></script>
    
    <script src="dist-systemjs.config.js"></script>
    <!-- Project Bundles. Note that these have to be loaded AFTER the systemjs.config script -->
    <script src="bundles/dependencies.bundle.js"></script>
    <script src="bundles/app.bundle.js"></script>
    
    <script>
        System.import('app/boot').catch(function (err) {
          console.error(err);
        });
    </script>
    </body>
    </html>
    
  • projectFolder / app / boot.ts is where the bootstrap is.

  • The best I could do yet :)


    Angular 2 with Webpack (without CLI setup)

    1- The tutorial by the Angular2 team

    The Angular2 team published a tutorial for using Webpack

    I created and placed the files from the tutorial in a small GitHub seed project. So you can quickly try the workflow.

    Instructions :

  • npm install

  • npm start . For development. This will create a virtual "dist" folder that will be livereloaded at your localhost address.

  • npm run build . For production. "This will create a physical "dist" folder version than can be sent to a webserver. The dist folder is 7.8MB but only 234KB is actually required to load the page in a web browser.

  • 2 - A Webkit starter kit

    This Webpack Starter Kit offers some more testing features than the above tutorial and seem quite popular.

    链接地址: http://www.djcxy.com/p/85572.html

    上一篇: 指向Java

    下一篇: 如何捆绑Angular应用程序进行生产