如何捆绑Angular应用进行生产


353

捆绑Angular(版本2、4、6,...)以在实时Web服务器上进行生产的最佳方法是什么。

请在答案中包括Angular版本,以便在移至更高版本时可以更好地进行跟踪。




RC3现在提供降低从300多个请求的数量约40捆绑的文件版本
帕特中号

2
嘿。我也讨厌WebPack的构建步骤。只是为了拼凑一个简单的网站而有点矫kill过正。因此,我做到了:github.com/schungx/angular2-bundle
Stephen Chung,

谢谢斯蒂芬。对于卖方而言,这将是一个简单的解决方案。希望可以正式提供和更新。我想您在项目的文件中使用了类似Gulp的东西吗?
Pat M

Answers:


361

2.x, 4.x, 5.x, 6.x, 7.x, 8.x, 9.x (TypeScript)与Angular CLI

一次性设置

  • npm install -g @angular/cli
  • ng new projectFolder 创建一个新的应用程序

捆绑步骤

  • ng build --prod(当目录为时,在命令行中运行projectFolder

    prod用于生产的标志包(有关生产标志的选项列表,请参阅Angular文档)。

  • 使用Brotli进行压缩使用以下命令压缩资源

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

捆绑包默认生成为projectFolder / dist(/ $ projectFolder for 6)

输出量

9.0.0带有CLI的Angular大小9.0.1和不带Angular路由的选件CSS

  • dist/main-[es-version].[hash].js您的应用程序捆绑了[ES5大小:158 KB,用于新的Angular CLI应用程序为空,压缩40 KB ]。
  • dist/polyfill-[es-version].[hash].bundle.js捆绑的polyfill依赖项(@angular,RxJS ...)[ES5大小:127 KB,用于新的Angular CLI应用程序为空,压缩37 KB ]。
  • dist/index.html 您的应用程序的入口点。
  • dist/runtime-[es-version].[hash].bundle.js Webpack加载器
  • dist/style.[hash].bundle.css 样式定义
  • dist/assets 从Angular CLI资产配置复制的资源

部署方式

您可以使用ng serve --prod启动本地HTTP服务器的命令来预览应用程序,以便使用http:// localhost:4200访问带有生产文件的应用程序。

对于生产用途,必须从dist您选择的HTTP服务器中的文件夹中部署所有文件。


运行npm install -g angular-cli @ webpack时出现错误:npm ERR!请在支持请求中包括以下文件:.... \ npm-debug.log。你知道发生了什么吗?
崇王

2
@chrismarx它仅产生一个捆绑包,其中包括所有具有html和样式的组件。
Nicolas Henneaux

4
我有一个应用程序,我想使用此方法,因此我从项目文件夹启动ng init。我已经完成了其余步骤,但是当我部署应用程序时,它似乎是空的。唯一出现的是“应用程序有效!” 消息,这是我必须设置应用程序文件存放位置的地方吗?
mautrok

2
ng-init已从角度cli中删除。github.com/angular/angular-cli/issues/5176
帕特中号

2
我最终将其标记为可接受的答案。尽管其他解决方案也可以工作,甚至可以提供一些额外的灵活性(我发布了一篇有关不使用CLI的Webpack的用法)。无疑,使用Angular CLI可以减少麻烦。我最终使用了Angular CLI并调整了项目,以便可以更轻松地使用AoT。
Pat M

57

2.0.1 Final 使用Gulp(TypeScript-目标:ES5)


一次性设置

  • npm install (当direcory是projectFolder时以cmd运行)

捆绑步骤

  • npm run bundle (当direcory是projectFolder时以cmd运行)

    束生成到projectFolder /束/

输出量

  • bundles/dependencies.bundle.js [ 大小:〜1 MB(尽可能小)]
    • 包含rxjs和角度依赖,而不是整个框架
  • bundles/app.bundle.js[ 大小:取决于您的项目,我的是〜0.5 MB ]
    • 包含您的项目

档案结构

  • projectFolder / app /(所有组件,指令,模板等)
  • 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(与快速入门指南相同,仅显示捆绑在一起所需的devDependencies和npm脚本)

{
  "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(与快速入门指南相同,现在不再可用)

(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(仅显示与systemjs.config.json的区别)

var map = {
    'app':                        'dist/app',
  };
  • projectFolder / index.html(生产)- 脚本标记的顺序很关键。将dist-systemjs.config.js标记放置在bundle标记之后仍将允许程序运行,但是依赖项捆绑将被忽略,并且将从node_modules文件夹中加载依赖项。

<!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是引导程序所在的位置。

我能做的最好的:)


2
嗨,gulp脚本正在创建捆绑包,但是我不确定boot.ts文件中应该包含什么?现在捆绑包中不是所有文件吗?我们执行捆绑软件吗?
chrismarx

2
嗯,我想我需要再试一次。我尝试切换到builder.buildStatic,并从rxjs收到有关未作为co​​mmonjs或amd模块加载的错误。我
将再

1
我还不清楚在此设置中如何实际使用捆绑软件?我似乎在这里遇到了与@chrismarx完全相同的问题。我可以创建捆绑包,但是似乎所有内容仍从我已编译和复制的应用程序文件夹(位于dist / app中)加载。如果我在网络面板中查看,则可以看到实际上是从那里加载与我的应用程序相关的文件(组件等),而不是所有与app.bundle.js相关的应用程序相关文件。A_Singh,可以分享您的boot.ts吗?看来我在这里遗漏了一些东西,希望您能澄清一下。
jbgarr

1
A_Singh,我看不出有什么帮助。当inline-templates运行它内联模板,然后在创建所有的应用程序文件夹和文件的副本dist/app。然后,如果您使用文件夹作为根目录,则在其中dist-systemjs.config.js映射的文件夹将不存在。您不想从该文件夹运行您的应用程序吗?如果是这种情况,您将不会在根文件夹中嵌套一个文件夹。我一定在这里想念其他东西。您不需要告诉systemjs使用捆绑的文件,而不是使用该文件夹中的普通文件吗?appdist/appdistdistdistdistdist/app
jbgarr

1
我在您的解决方案中遇到问题,启动是这里不存在的问题,当我将其替换为“ app”时,出现错误“模块未定义”。
LoïcR

22

带有Webpack的Angular 2(无CLI设置)

1- Angular2团队的教程

Angular2团队发布了有关使用Webpack 的教程

我创建了教程中的文件并将其放置在一个GitHub种子项目中。因此,您可以快速尝试工作流程。

说明

  • npm安装

  • npm开始。为了发展。这将创建一个虚拟的“ dist”文件夹,该文件夹将实时重载到您的本地主机地址。

  • npm运行构建。用于生产。“这将创建一个物理的“ dist”文件夹版本,然后发送到Web服务器。dist文件夹为7.8MB,但实际上仅需要234KB即可在Web浏览器中加载页面。

2-Webkit入门套件

Webpack入门工具包提供了比上述教程更多的测试功能,并且似乎很受欢迎。


嗨,有可能用角度2.1.0更新种子项目吗?本教程现在使用angular 2.1.0。我遵循了它,但无法使其正常工作。错误是http 404-找不到app.component.html。
heq99

我已更新为angular 2.1.0,没有问题。从app.component.ts(templateUrl:'./app.component.html')中调用app.component.html。您将两个文件都放在同一个应用程序文件夹中?
Pat M

1
进行生产时,摇树,缩小和压缩可以大大减小尺寸。这是一个很好的示例阅读,blog.mgechev.com
2016/

16

使用SystemJs builder和gulp进行Angular 2生产工作流程

Angular.io有快速入门教程。我复制了本教程,并扩展了一些简单的gulp任务,将所有内容捆绑到dist文件夹中,这些文件夹可以复制到服务器并像这样工作。我试图优化所有内容以使其在Jenkis CI上正常工作,因此可以缓存node_modules,而无需复制。

Github上的示例应用程序的源代码: https //github.com/Anjmao/angular2-production-workflow

生产步骤
  1. 清理打字稿编译的js文件和dist文件夹
  2. 编译应用文件夹中的打字稿文件
  3. 使用SystemJs捆绑程序将所有内容捆绑到具有生成的哈希值的dist文件夹中,以刷新浏览器缓存
  4. 使用gulp-html-replace用捆绑的版本替换index.html脚本并复制到dist文件夹
  5. 将资产文件夹中的所有内容复制到dist文件夹

Node:虽然您总是可以创建自己的构建过程,但是我强烈建议使用angular-cli,因为它具有所有必需的工作流程,并且现在可以完美运行。我们已经在生产中使用它,而angular-cli完全没有任何问题。


这就是我要的东西。github上的示例应用程序非常有用。谢谢
Shahriar Hasan Sayeed

14

Angular CLI 1.xx(适用于Angular 4.xx,5.xx)

这支持:

  • 角2.x和4.x
  • 最新的Webpack 2.x
  • Angular AoT编译器
  • 路由(正常和延迟)
  • SCSS
  • 自定义文件捆绑(资产)
  • 其他开发工具(线性,单元和端到端测试设置)

最初设定

ng new project-name --routing

您可以添加--style=scss对SASS .scss的支持。

您可以添加--ng4使用Angular 4而不是Angular 2。

创建项目后,CLI将自动npm install为您运行。如果您想改用Yarn,或者只想查看项目骨架而不进行安装,请在此处查看操作方法

捆绑步骤

在项目文件夹中:

ng build -prod

在当前版本中,您需要指定 --aot手动,因为它可以在开发模式下使用(尽管由于运行缓慢而无法使用)。

这还将对更小的捆绑包(没有Angular编译器,而是生成的编译器输出)执行AoT编译。如果您使用Angular 4,则使用AoT的捆绑包会更小,因为生成的代码会更小。
您可以通过在开发模式下使用AoT(源地图,无缩小)和AoT来测试您的应用,方法是运行ng build --aot

输出量

./dist尽管可以在中更改默认输出目录./angular-cli.json

可部署文件

构建步骤的结果如下:

(注意:<content-hash>指的是文件内容的哈希/指纹,这是一种缓存清除方式,这是可能的,因为Webpack会自行编写script标签)

  • ./dist/assets
    原样复制的文件来自 ./src/assets/**
  • ./dist/index.html
    从中./src/index.html添加Webpack脚本后,从中,可在以下
    位置配置源模板文件./angular-cli.json
  • ./dist/inline.js
    小型Webpack装载机/ Polyfill
  • ./dist/main.<content-hash>.bundle.js
    主.js文件,包含所有生成/导入的.js脚本
  • ./dist/styles.<content-hash>.bundle.js
    当您将Webpack加载程序用于CLI(即CLI方式)时,可通过JS在此处加载它们

在较旧的版本中,它还创建了压缩版本以检查其大小和.mapsourcemaps文件,但是由于人们不断要求删除这些文件,因此不再发生这种情况。

其它文件

在某些其他情况下,您可能会发现其他不需要的文件/文件夹:

  • ./out-tsc/
    来自./src/tsconfig.jsonoutDir
  • ./out-tsc-e2e/
    来自./e2e/tsconfig.jsonoutDir
  • ./dist/ngfactory/
    从AoT编译器开始(如果不从beta 16开始分叉CLI,则无法配置)

是否可以从我的应用程序中分离出角度库及其依赖项?
多米尼克·皮加内尔

不使用CLI,这是为了使树摇晃而起作用的。那就是删除应用程序中未使用的所有Angular EcmaScript模块。有计划在开发模式下禁用此功能以提高速度(它们将库称为“ DLL”加载),但没有计划将最终结果分开。如果您在没有CLI的情况下滚动自己的Webpack内容,则应该可以实现。
Meligy '16

如何使用dist文件夹检查我的应用程序。如何在我的Web服务器上托管?
raj m

您只需将其复制到服务器。这是可以通过任何方式提供的纯静态网站。如果您使用路由,则可能需要将所有调用重定向到HTML文件,为此,请检查服务器配置上的Angular部署文档部分angular.io/docs/ts/latest/guide/…–
Meligy

@Meligy如果我<content-hash>从产品包中删除,该怎么办。它可能会导致在获取最新的捆绑软件时出现问题?
k11k2

5

直到今天,我仍然发现《提前编译》食谱是生产捆绑的最佳方法。您可以在这里找到它:https : //angular.io/docs/ts/latest/cookbook/aot-compiler.html

到目前为止,我对Angular 2的经验是AoT创建了最小的构建,几乎没有加载时间。最重要的是这里的问题-您只需要将几个文件发送到生产环境即可。

这似乎是因为Angular编译器不会随生产版本一起提供,因为模板是“提前”编译的。看到HTML模板标记转换为javascript指令(将其反向工程为原始HTML十分困难)也很酷。

我制作了一个简单的视频,演示了在开发vs AoT构建中Angular 2应用程序的下载大小,文件数等-您可以在此处查看:

https://youtu.be/ZoZDCgQwnmQ

您可以在此处找到视频中使用的源代码:

https://github.com/fintechneo/angular2-templates


3
        **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="https://stackoverflow.com/">
    </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.

2

您可以github使用 angular-cli-ghpages部署您的angular应用程序

请查看链接以找到如何使用此cli进行部署。

已部署的网站将被存储在某个分支的github典型

gh页

use可以克隆git分支,并像在服务器中使用静态网站一样使用它


1

“最佳”取决于场景。有时候,您只关心最小的单个捆绑包,但是在大型应用程序中,您可能不得不考虑延迟加载。在某个时候,将整个应用程序作为一个捆绑包提供是不切实际的。

在后一种情况下,Webpack通常是最好的方法,因为它支持代码拆分。

对于单个捆绑包,如果您觉得很勇敢,可以考虑使用汇总,或Closure编译器:-)

我已经创建了我在这里使用过的所有Angular捆绑器的示例:http : //www.syntaxsuccess.com/viewarticle/angular-production-builds

该代码可以在这里找到: https //github.com/thelgevold/angular-2-samples

角度版本:4.1.x



0

请在当前项目目录中尝试以下CLI命令。它将创建dist文件夹包。因此您可以上传dist文件夹中的所有文件以进行部署。

ng build --prod --aot --base-href。


0

ng服务作品,用于为开发目的服务我们的应用程序。生产呢?如果我们查看package.json文件,可以看到可以使用以下脚本:

"scripts": {
  "ng": "ng",
  "start": "ng serve",
  "build": "ng build --prod",
  "test": "ng test",
  "lint": "ng lint",
  "e2e": "ng e2e"
},

构建脚本使用带有--prod标志的Angular CLI的ng构建。让我们现在尝试。我们可以通过以下两种方式之一进行操作:

#使用npm脚本

npm run build

#直接使用cli

ng build --prod

这次我们得到的是四个文件,而不是五个。--prod标志告诉Angular使我们的应用程序更小。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.