What is the best method to bundle Angular (version 2, 4, 6, ...) 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.
What is the best method to bundle Angular (version 2, 4, 6, ...) 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 to 17
(TypeScript) with Angular CLInpm install -g @angular/cli
ng new projectFolder
creates a new applicationng build
(run in command line when directory is projectFolder
).
flag prod
bundle for production is now the default (see the Angular documentation to customize it if needed).
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{/,/browser} for v6+)
Sizes with Angular 17.0.9
and option CSS without pre-rendering
dist/main.[hash].js
Your application bundled [ size: 193 KB for new Angular CLI application empty, 53 KB compressed].dist/polyfill-[es-version].[hash].bundle.js
the polyfill dependencies (@angular, RxJS...) bundled [ size: 33 KB for new Angular CLI application empty, 11 KB compressed].dist/index.html
entry point of your application.dist/runtime.[hash].bundle.js
webpack loaderdist/style.[hash].bundle.css
the style definitionsdist/assets
resources copied from the Angular CLI assets configurationYou 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. This is not safe to use for production usage.
For a production usage, you have to deploy all the files from the dist
folder in the HTTP server of your choice.
npm install [email protected]
does the trick. However, I had to apply this patch to fix the "TypeError: path must be a string or Buffer" problem described in issue 2135 –
Sethrida ng init
i get Cannot find module 'portfinder'
–
Trail ng server --prod --aot
that start an HTTP server with production files with Angular CLI or use an external HTTP server with the file from the dist
folder. –
Paluas for i in dist/*; do bro --input $i --output $i.br; done
) –
Paluas bro
command for Brotli compression in Windows? –
Hooky for i in dist/*; do brotli $i; done
–
Orlan dist
folder is located –
Paluas 2.0.1 Final
using Gulp (TypeScript - Target: ES5)npm install
(run in cmd when direcory is projectFolder)npm run bundle
(run in cmd when direcory is projectFolder)
bundles are generated to projectFolder / bundles /
bundles/dependencies.bundle.js
[ size: ~ 1 MB (as small as possible) ]
bundles/app.bundle.js
[ size: depends on your project, mine is ~ 0.5 MB ]
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);
});
});
{
"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"
}
}
(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);
var map = {
'app': 'dist/app',
};
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>
The best I could do yet :)
System.import('app/boot')
in index.html is for SystemJS it's the starting point for your app, it's loaded from bundle, you don't need boot.ts
after bundle –
Wicker dist-systemjs.config.js
in index.html
in which app
maps to dist/app
–
Wicker inline-templates
is run it inlines the templates then creates a copy of all app folders and files at dist/app
. Then in dist-systemjs.config.js
you map app
to dist/app
which is a folder that won't exist if you use the dist
folder as root. Wouldn't you want to run your app from the dist
folder? And if that's the case, you wouldn't have a dist
folder nested in the root dist
folder. I must be missing something else here. Don't you need to tell systemjs to use your bundled files and not the usual files found in the dist/app
folder? –
Charleencharlemagne systemjs.config.js
files being referenced in my app. That was all the result of trying too many different bundling approaches. I was actually including one systemjs.config.js
file already when bundling some core js files like zone.js
and reflect.js
. That was throwing all kinds of things off like actually trying to look for files located in a nested dist/app
folder... The magic of systemjs
was confusing me as well. –
Charleencharlemagne dist/app
does not exist but system.js
does not go to look for it because we have bundled it in the bundle. –
Wicker dependencies.bundle.js
file at run time, everything else from your answer works great. I can see the dependencies.bundle.js
loaded in the browser dev console under my sources but the browser console shows all the dependencies being loaded from node_modules
. Also in the gulpfile.js
I had to change the exclusions and include the node_modules/
folder prefix so by app.bundle.js
would not include the dependencies. Any idea as to where/what I should check? Also thank you for the great answer. –
Estellaestelle dist-systemjs.config.js
instead of systemjs.config.js
, there is a slight difference in mapping. should fix the problem, i think. ` ` ` ` You're welcome :) –
Wicker index.html
file. I have posted the [question on SO ](https://mcmap.net/q/66165/-systemjs-ignores-angular-dependency-bundle/1260204) with all of the details. I hope maybe you have time to shed some light on it for me. Thank you again. –
Estellaestelle 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.
This Webpack Starter Kit offers some more testing features than the above tutorial and seem quite popular.
Angular.io have quick start tutorial. I copied this tutorial and extended with some simple gulp tasks for bundling everything to dist folder which can be copied to server and work just like that. I tried to optimize everything to work well on Jenkis CI, so node_modules can be cached and don't need to be copied.
Source code with sample app on Github: https://github.com/Anjmao/angular2-production-workflow
Steps to productionNode: While you always can create your own build process, but I highly recommend to use angular-cli, because it have all needed workflows and it works perfectly now. We are already using it in production and don't have any issues with angular-cli at all.
This supports:
ng new project-name --routing
You can add --style=scss
for SASS .scss support.
You can add --ng4
for using Angular 4 instead of Angular 2.
After creating the project, the CLI will automatically run npm install
for you. If you want to use Yarn instead, or just want to look at the project skeleton without install, check how to do it here.
Inside the project folder:
ng build -prod
At the current version you need to to specify --aot
manually, because it can be used in development mode (although that's not practical due to slowness).
This also performs AoT compilation for even smaller bundles (no Angular compiler, instead, generated compiler output). The bundles are much smaller with AoT if you use Angular 4 as the generated code is smaller.
You can test your app with AoT in development mode (sourcemaps, no minification) and AoT by running ng build --aot
.
The default output dir is ./dist
, although it can be changed in ./angular-cli.json
.
The result of build step is the following:
(Note: <content-hash>
refers to hash / fingerprint of the contents of the file that's meant to be a cache busting way, this is possible since Webpack writes the script
tags by itself)
./dist/assets
./src/assets/**
./dist/index.html
./src/index.html
, after adding webpack scripts to it./angular-cli.json
./dist/inline.js
./dist/main.<content-hash>.bundle.js
./dist/styles.<content-hash>.bundle.js
In older versions it also created gzipped versions for checking their size, and .map
sourcemaps files, but this is no longer happening as people kept asking to remove these.
In certain other occasions, you might find other unwanted files/folders:
./out-tsc/
./src/tsconfig.json
's outDir
./out-tsc-e2e/
./e2e/tsconfig.json
's outDir
./dist/ngfactory/
<content-hash>
from the bundles in prod. it may cause problems in getting latest bundle ? –
Chaste As of today I still find the Ahead-of-Time Compilation cookbook as the best recipe for production bundling. You can find it here: https://angular.io/docs/ts/latest/cookbook/aot-compiler.html
My experience with Angular 2 so far is that AoT creates the smallest builds with almost no loading time. And most important as the question here is about - you only need to ship a few files to production.
This seems to be because the Angular compiler will not be shipped with the production builds as the templates are compiled "Ahead of Time". It's also very cool to see your HTML template markup transformed to javascript instructions that would be very hard to reverse engineer into the original HTML.
I've made a simple video where I demonstrate download size, number of files etc. for an Angular 2 app in dev vs AoT build - which you can see here:
You'll find the source code used in the video here:
ng build --configuration production (angular 14 onwards)
**Production build with
- Angular Rc5
- Gulp
- typescripts
- systemjs**
1)con-cat all js files and css files include on index.html using "gulp-concat".
- styles.css (all css concat in this files)
- shims.js(all js concat in this files)
2)copy all images and fonts as well as html files with gulp task to "/dist".
3)Bundling -minify angular libraries and app components mentioned in systemjs.config.js file.
Using gulp 'systemjs-builder'
SystemBuilder = require('systemjs-builder'),
gulp.task('system-build', ['tsc'], function () {
var builder = new SystemBuilder();
return builder.loadConfig('systemjs.config.js')
.then(function () {
builder.buildStatic('assets', 'dist/app/app_libs_bundle.js')
})
.then(function () {
del('temp')
})
});
4)Minify bundles using 'gulp-uglify'
jsMinify = require('gulp-uglify'),
gulp.task('minify', function () {
var options = {
mangle: false
};
var js = gulp.src('dist/app/shims.js')
.pipe(jsMinify())
.pipe(gulp.dest('dist/app/'));
var js1 = gulp.src('dist/app/app_libs_bundle.js')
.pipe(jsMinify(options))
.pipe(gulp.dest('dist/app/'));
var css = gulp.src('dist/css/styles.min.css');
return merge(js,js1, css);
});
5) In index.html for production
<html>
<head>
<title>Hello</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8" />
<link rel="stylesheet" href="app/css/styles.min.css" />
<script type="text/javascript" src="app/shims.js"></script>
<base href="/">
</head>
<body>
<my-app>Loading...</my-app>
<script type="text/javascript" src="app/app_libs_bundle.js"></script>
</body>
</html>
6) Now just copy your dist folder to '/www' in wamp server node need to copy node_modules in www.
You can deploy your angular application on github
using
angular-cli-ghpages
check out the link to find how to deploy using this cli.
the deployed website will be stored in some branch in github
typically
gh-pages
use can clone the git branch and use it like static website in your server
"Best" depends on the scenario. There are times when you only care about the smallest possible single bundle, but in large apps you may have to consider lazy loading. At some point it becomes impractical to serve the entire app as a single bundle.
In the latter case Webpack is generally the best way since it supports code splitting.
For a single bundle I would consider Rollup, or the Closure compiler if you are feeling brave :-)
I have created samples of all Angular bundlers I've ever used here: http://www.syntaxsuccess.com/viewarticle/angular-production-builds
The code can be found here: https://github.com/thelgevold/angular-2-samples
Angular version: 4.1.x
ng serve works for serving our application for development purposes. What about for production? If we look into our package.json file, we can see that there are scripts we can use:
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build --prod",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
The build script uses the Angular CLI's ng build with the --prod flag. Let's try that now. We can do it one of two ways:
# using the npm scripts
npm run build
# using the cli directly
ng build --prod
This time we are given four files instead of the five. The --prod flag tells Angular to make our application much smaller in size.
Just setup angular 4 with webpack 3 within a minute your development and production ENV bundle will become ready without any issue just follow the below github doc
Please try below CLI command in current project directory. It will create dist folder bundle. so you can upload all files within dist folder for deployments.
ng build --prod --aot --base-href.
Kindly use the following cmd in your terminal
ng build --configuration production --aot
© 2022 - 2024 — McMap. All rights reserved.