如何捆绑Angular应用程序进行生产

Pat*_*t M 337 systemjs webpack angular-cli angular

我想在这个帖子中跟踪和更新最新的(并且希望是最简单的)方法来捆绑Angular(版本2,4,...)以便在实时Web服务器上进行生产.

请在答案中包含Angular版本,以便我们可以更好地跟踪它何时转移到更高版本.

Nic*_*aux 340

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

OneTime设置

  • 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)

产量

使用8.2.11带有CLI的Angular 8.3.13和没有Angular路由的选项CSS的大小

  • dist/main-[es-version].[hash].js您的应用程序捆绑[大小:151 KB,新的Angular CLI应用程序为空,37 KB压缩].
  • dist/polyfill-[es-version].[hash].bundle.jspolyfill依赖项(@angular,RxJS ...)捆绑[大小:41 KB,新Angular CLI应用程序为空,12 KB压缩].
  • dist/index.html 申请的入口点.
  • dist/runtime-[es-version].[hash].bundle.js webpack loader
  • dist/style.[hash].bundle.css 风格定义
  • dist/assets 从Angular CLI资产配置复制的资源

部署

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

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

  • 我有一个应用程序,我想使用这个方法,所以我从项目文件夹启动ng init.我已经完成了其余的步骤,但是当我部署我的应用程序时,它似乎是空的.唯一出现的是"app works!" 消息,在某些地方,我必须设置在哪里采取我的应用程序文件? (4认同)
  • @chrismarx它只生成一个包,包括所有具有html和样式的组件. (2认同)
  • ng-init已从角度cli中删除.https://github.com/angular/angular-cli/issues/5176 (2认同)
  • 我终于将此标记为已接受的答案.虽然其他解决方案也可以工作,甚至提供一些额外的灵活性(我发布了一个关于在没有CLI的情况下使用Webpack).使用Angular CLI绝对是一个让人头疼的问题.我最终使用Angular CLI并调整我的项目,因此我可以更轻松地使用AoT. (2认同)

Ank*_*ngh 54

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


OneTime设置

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

捆绑步骤

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

    捆绑包生成到projectFolder/bundles /

产量

  • 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);
    });
});
Run Code Online (Sandbox Code Playgroud)
  • projectFolder/package.json(与Quickstart指南相同,只显示了捆绑所需的devDependencies和npm-scripts)

{
  "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"
  }
}
Run Code Online (Sandbox Code Playgroud)

(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);
Run Code Online (Sandbox Code Playgroud)
  • projetcFolder/dist-systemjs.config.js(刚刚显示与systemjs.config.json的区别)

var map = {
    'app':                        'dist/app',
  };
Run Code Online (Sandbox Code Playgroud)
  • 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>
Run Code Online (Sandbox Code Playgroud)
  • projectFolder/app/boot.ts是引导程序所在的位置.

我能做的最好:)

  • 嗨,gulp脚本正在创建捆绑包,但我不确定boot.ts文件中应该包含哪些内容?现在捆绑中的所有文件都不是吗?我们执行捆绑吗? (2认同)
  • 嗯,我想我需要再试一次.我尝试切换到builder.buildStatic并从rxjs获得有关未作为co​​mmonjs或amd模块加载的错误.我会再给你一个建议 (2认同)

Pat*_*t M 22

带Webpack的Angular 2(不带CLI设置)

1- Angular2团队的教程

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

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

说明:

  • npm安装

  • npm开始.为了发展.这将创建一个虚拟的"dist"文件夹,该文件夹将在您的localhost地址中进行实时加载.

  • npm run build.用于生产."这将创建一个物理"dist"文件夹版本,而不是可以发送到网络服务器.dist文件夹是7.8MB,但实际上只需要234KB即可在网络浏览器中加载页面.

2 - Webkit入门套件

这个Webpack入门套件提供了比上述教程更多的测试功能,看起来很受欢迎.


And*_*vic 15

使用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. 编译app文件夹中的打字稿文件
  3. 使用SystemJs bundler将所有内容捆绑到dist文件夹,生成的哈希值用于浏览器缓存刷新
  4. 使用gulp-html-replace将index.html脚本替换为捆绑版本并复制到dist文件夹
  5. 将assets文件夹中的所有内容复制到dist文件夹

节点:虽然你总是可以创建自己的构建过程,但我强烈建议使用angular-cli,因为它具有所有需要的工作流程,现在它可以很好地工作.我们已经在生产中使用它,并且根本没有任何与angular-cli有关的问题.


Mel*_*igy 14

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

这支持:

  • Angular 2.x和4.x.
  • 最新的Webpack 2.x
  • Angular AoT编译器
  • 路由(正常和懒惰)
  • SCSS
  • 自定义文件捆绑(资产)
  • 其他开发工具(linter,unit和end-to-end测试设置)

初始设置

ng new project-name --routing

您可以添加--style=scssSASS .scss支持.

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

创建项目后,CLI将自动npm install为您运行.如果您想要使用Yarn,或者只想在没有安装的情况下查看项目框架,请在此处查看如何执行此操作.

捆绑步骤

在项目文件夹中:

ng build -prod

在当前版本中,您需要--aot手动指定,因为它可以在开发模式下使用(尽管由于速度慢而不实用).

这也为更小的bundle执行AoT编译(没有Angular编译器,而是生成的编译器输出).如果使用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
    当您使用CSS的CSSpack加载器(这是CLI方式)时,它们通过JS加载

在旧版本中,它还创建了用于检查其大小和.map源映射文件的gzip压缩版本,但这种情况不再发生,因为人们一直要求删除它们.

其他文件

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

  • ./out-tsc/
    来自./src/tsconfig.jsonoutDir
  • ./out-tsc-e2e/
    来自./e2e/tsconfig.jsonoutDir
  • ./dist/ngfactory/
    来自AoT编译器(从beta 16开始不配置CLI而不配置)


Pet*_*sen 5

截至今天,我仍然发现Ahead-of-Time Compilation cookbook是生产捆绑的最佳配方.你可以在这里找到它:https://angular.io/docs/ts/latest/cookbook/aot-compiler.html

到目前为止,我对Angular 2的体验是,AoT创建了最小的构建,几乎没有加载时间.最重要的是这里的问题是 - 您只需要将一些文件发送到生产中.

这似乎是因为Angular编译器不会随生产版本一起提供,因为模板是"提前"编译的.将HTML模板标记转换为javascript指令也非常酷,这些指令很难在原始HTML中进行逆向工程.

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

https://youtu.be/ZoZDCgQwnmQ

你会在这里找到视频中使用的源代码:

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