Como agrupar um aplicativo Angular para produção

353

Qual é o melhor método para agrupar o Angular (versão 2, 4, 6, ...) para produção em um servidor da web ao vivo.

Inclua a versão Angular nas respostas para que possamos acompanhar melhor quando ela for lançada posteriormente.

Pat M
fonte
Por enquanto (rc1). Aqui estão algumas soluções stackoverflow.com/questions/37324511/how-to-bundle-angular2-rc1-with-systemjs
Pat M
RC3 agora oferece versões de arquivos em pacotes que reduz o número de pedidos de mais de 300 para cerca de 40.
Pat M
2
Ei. Eu também odeio WebPack e construo etapas em geral. Meio que exagero por apenas tentar criar um site simples. Assim, fiz o seguinte: github.com/schungx/angular2-bundle #
Stephen Chung #
Obrigado Stephen. Essa seria uma solução simples para a parte dos fornecedores. Esperando que isso possa ser oferecido e atualizado oficialmente. Suponho que você use algo como Gulp para os arquivos do projeto.
Pat M

Respostas:

362

2.x, 4.x, 5.x, 6.x, 7.x, 8.x, 9.x (TypeScript) com CLI angular

Configuração do OneTime

  • npm install -g @angular/cli
  • ng new projectFolder cria um novo aplicativo

Etapa de agrupamento

  • ng build --prod(executado na linha de comandos quando o diretório estiver projectFolder)

    prodPacote de sinalizadores para produção (consulte a documentação Angular para obter a lista de opções incluídas no sinalizador de produção).

  • Compactar usando Brotli compacta os recursos usando o seguinte comando

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

os pacotes configuráveis são gerados por padrão para projectFolder / dist (/ $ projectFolder for 6)

Resultado

Tamanhos com Angular 9.0.0com CLI 9.0.1e opção CSS sem roteamento Angular

  • dist/main-[es-version].[hash].jsSeu aplicativo empacotou [tamanho do ES5: 158 KB para o novo aplicativo CLI Angular vazio, 40 KB compactado].
  • dist/polyfill-[es-version].[hash].bundle.jsas dependências do polyfill (@angular, RxJS ...) empacotadas [tamanho ES5: 127 KB para o novo aplicativo CLI Angular vazio, 37 KB compactado].
  • dist/index.html ponto de entrada da sua aplicação.
  • dist/runtime-[es-version].[hash].bundle.js carregador webpack
  • dist/style.[hash].bundle.css as definições de estilo
  • dist/assets recursos copiados da configuração de ativos da CLI Angular

Desdobramento, desenvolvimento

Você pode obter uma visualização do seu aplicativo usando o ng serve --prodcomando que inicia um servidor HTTP local, para que o aplicativo com arquivos de produção seja acessível usando http: // localhost: 4200 .

Para um uso de produção, você deve implantar todos os arquivos da distpasta no servidor HTTP de sua escolha.

Nicolas Henneaux
fonte
Eu recebi o erro ao executar o npm install -g angular-cli @ webpack: npm ERR! Inclua o seguinte arquivo em qualquer solicitação de suporte: .... \ npm-debug.log. Você sabe o que está acontecendo?
Chong Wang
2
@chrismarx produz apenas um pacote, incluindo todos os componentes, com html e estilos.
Nicolas Henneaux 27/09/16
4
Eu tinha um aplicativo e queria usar esse método, então inicio o init a partir da pasta do projeto. Eu fiz as demais etapas, mas quando implanto meus aplicativos, ele parece estar vazio. A única coisa que aparece é um "aplicativo funciona!" mensagem, existe algum lugar onde eu tenho que definir para onde levar meus arquivos de aplicativos?
Mautrok # 25/16
2
ng-init foi removido do cli angular. github.com/angular/angular-cli/issues/5176
Pat M
2
Finalmente marquei isso como a resposta aceita. Embora outras soluções possam funcionar bem e até fornecer alguma flexibilidade extra (eu postei uma sobre o uso do Webpack sem CLI). O uso da CLI angular é definitivamente o que causa menos dores de cabeça. Acabei usando o Angular CLI e adaptando meu projeto para poder usar o AoT mais facilmente.
Pat M
57

2.0.1 Final usando Gulp (TypeScript - Destino: ES5)


Configuração do OneTime

  • npm install (executado no cmd quando direcory é projectFolder)

Etapas de agrupamento

  • npm run bundle (executado no cmd quando direcory é projectFolder)

    pacotes são gerados para projectFolder / bundles /

Resultado

  • bundles/dependencies.bundle.js[ tamanho: ~ 1 MB (o menor possível)]
    • contém rxjs e dependências angulares, não as estruturas inteiras
  • bundles/app.bundle.js[ tamanho: depende do seu projeto , o meu é ~ 0,5 MB ]
    • contém seu projeto

Estrutura do arquivo

  • projectFolder / app / (todos os componentes, diretivas, modelos 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 (o mesmo do guia de início rápido , apenas mostramos devDependencies e npm-scripts necessários para agrupar)

{
  "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);
  • projetcFolder / dist-systemjs.config.js (apenas mostramos a diferença com systemjs.config.json)

var map = {
    'app':                        'dist/app',
  };
  • projectFolder / index.html (produção) - A ordem das tags de script é crítica. A colocação da dist-systemjs.config.jstag após as tags do pacote configurável ainda permitiria a execução do programa, mas o pacote configurável de dependência seria ignorado e as dependências seriam carregadas da node_modulespasta.

<!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 é o local da inicialização.

O melhor que pude fazer ainda :)

Ankit Singh
fonte
2
Olá, o script gulp está criando os pacotes, mas não tenho certeza do que deve estar no arquivo boot.ts? Agora, todos os arquivos não estão no pacote? Nós executamos o pacote?
chrismarx
2
Acho que preciso tentar novamente. Tentei mudar para builder.buildStatic e obtive erros do rxjs por não serem carregados como um módulo commonjs ou amd. Vou tentar outra vez a sua sugestão
Chrismarx
11
Também não estou claro como os pacotes realmente são usados ​​nessa configuração? Parece que estou tendo exatamente os mesmos problemas que o @chrismarx aqui. Posso criar os pacotes, mas parece que tudo ainda está sendo carregado da minha pasta de aplicativos transpilada e copiada (localizada em dist / app). Se eu olhar no meu painel de rede, posso ver que meus arquivos relacionados ao aplicativo estão realmente sendo carregados a partir dali (componentes, etc.), em vez de tudo o que está relacionado ao aplicativo vindo de app.bundle.js. A_Singh, você pode compartilhar o seu boot.ts? Parece que estou perdendo alguma coisa aqui e gostaria de alguns esclarecimentos.
Jbgarr # 9/16
11
A_Singh, não vejo como isso ajuda. Quando inline-templatesé executado, ele inline os modelos e cria uma cópia de todas as pastas e arquivos do aplicativo em dist/app. Em seguida, dist-systemjs.config.jsvocê mapeia apppara a dist/appqual existe uma pasta que não existirá se você a usar distcomo raiz. Você não gostaria de executar seu aplicativo a partir da distpasta? E se for esse o caso, você não teria uma distpasta aninhada na distpasta raiz . Eu devo estar perdendo algo mais aqui. Você não precisa dizer ao systemjs para usar seus arquivos agrupados e não os arquivos habituais encontrados na dist/apppasta?
Jbgarr #
11
Estou com um problema com sua solução, a inicialização é algo que não existe aqui e, quando a substituo por "app", tenho um erro "o módulo não está definido".
LoïcR
22

Angular 2 com Webpack (sem configuração da CLI)

1- O tutorial da equipe Angular2

A equipe do Angular2 publicou um tutorial para usar o Webpack

Criei e coloquei os arquivos do tutorial em um pequeno projeto de semente do GitHub . Para que você possa experimentar rapidamente o fluxo de trabalho.

Instruções :

  • instalação npm

  • npm start . Para desenvolvimento. Isso criará uma pasta virtual "dist" que será carregada no seu endereço do host local.

  • npm executar compilação . Para produção. "Isso criará uma versão física da pasta" dist "que pode ser enviada para um servidor da Web. A pasta dist é de 7,8 MB, mas apenas 234 KB são realmente necessários para carregar a página em um navegador da Web.

2 - Um kit inicial do Webkit

Este Webpack Starter Kit oferece mais recursos de teste que o tutorial acima e parece bastante popular.

Pat M
fonte
oi, é possível atualizar o projeto de semente com angular 2.1.0? O tutorial está usando o angular 2.1.0 agora. Eu o segui e não consegui fazê-lo funcionar. O erro é http 404 - não foi possível encontrar o app.component.html.
heq99
Atualizei para o angular 2.1.0 sem problemas. app.component.html é chamado de app.component.ts (templateUrl: './app.component.html'). você tem os dois arquivos na mesma pasta do aplicativo?
Pat M
11
A trepidação de árvores, a Minificação e o Gzipping podem reduzir bastante o tamanho da produção. aqui está uma excelente leitura com exemplo, blog.mgechev.com/2016/06/26/…
Hamzeen Hameem
16

Fluxo de trabalho de produção angular 2 com o construtor SystemJs e gulp

Angular.io tem tutorial de início rápido. Copiei este tutorial e estendi algumas tarefas simples para agrupar tudo na pasta dist, que pode ser copiada para o servidor e funcionar assim. Tentei otimizar tudo para funcionar bem no Jenkis CI, para que o node_modules possa ser armazenado em cache e não precise ser copiado.

Código-fonte com aplicativo de exemplo no Github: https://github.com/Anjmao/angular2-production-workflow

Etapas para a produção
  1. Arquivos de texto limpo compilados js e pasta dist
  2. Compilar arquivos datilografados dentro da pasta do aplicativo
  3. Use o bundler SystemJs para agrupar tudo na pasta dist com hashes gerados para atualização do cache do navegador
  4. Use gulp-html-replace para substituir os scripts index.html por versões em pacote e copie para a pasta dist
  5. Copie tudo dentro da pasta de ativos para a pasta dist

: Embora você sempre possa criar seu próprio processo de criação, mas eu recomendo usar o angular-cli, porque ele possui todos os fluxos de trabalho necessários e funciona perfeitamente agora. Já o estamos usando na produção e não temos nenhum problema com o angular-cli.

Andzej Maciusovic
fonte
É isso que estou procurando. Aplicativo de exemplo no github é muito útil. Obrigado
Shahriar Hasan Sayeed
14

CLI angular 1.xx (funciona com Angular 4.xx, 5.xx)

Isso suporta:

  • Angular 2.xe 4.x
  • Webpack 2.x mais recente
  • Compilador Angular AoT
  • Roteamento (normal e preguiçoso)
  • SCSS
  • Agrupamento de arquivos personalizado (ativos)
  • Ferramentas de desenvolvimento adicionais (configurações de linter, unidade e teste de ponta a ponta)

Configuração inicial

ng new project-name --routing

Você pode adicionar --style=scssao suporte ao SASS .scss.

Você pode adicionar o --ng4Angular 4 em vez do Angular 2.

Após criar o projeto, a CLI será executada automaticamente npm installpara você. Se você deseja usar o Yarn, ou apenas deseja ver o esqueleto do projeto sem instalar, verifique como fazê-lo aqui .

Etapas do pacote

Dentro da pasta do projeto:

ng build -prod

Na versão atual, você precisa especificar --aot manualmente, porque pode ser usado no modo de desenvolvimento (embora isso não seja prático devido à lentidão).

Isso também executa a compilação AoT para pacotes ainda menores (nenhum compilador Angular, em vez disso, gerou saída do compilador). Os pacotes configuráveis ​​são muito menores com o AoT se você usar o Angular 4, pois o código gerado é menor.
Você pode testar seu aplicativo com o AoT no modo de desenvolvimento (mapas de origem, sem minificação) e o AoT executandong build --aot .

Resultado

O diretório de saída padrão é ./dist, embora possa ser alterado ./angular-cli.json.

Arquivos implantáveis

O resultado da etapa de construção é o seguinte:

(Nota: <content-hash>refere-se ao hash / impressão digital do conteúdo do arquivo que deve ser uma maneira de impedir o cache, isso é possível, pois o Webpack grava as scripttags sozinho)

  • ./dist/assets
    Arquivos copiados como estão de ./src/assets/**
  • ./dist/index.html
    A partir ./src/index.html, depois de adicionar scripts de Webpack a ele
    arquivo de modelo Fonte está em configurável./angular-cli.json
  • ./dist/inline.js
    Carregador webpack pequeno / de polifill
  • ./dist/main.<content-hash>.bundle.js
    O arquivo .js principal que contém todos os scripts .js gerados / importados
  • ./dist/styles.<content-hash>.bundle.js
    Quando você usa carregadores Webpack para CSS, que é o caminho da CLI, eles são carregados via JS aqui

Nas versões mais antigas, também criava versões compactadas com gzip para verificar o tamanho e os .maparquivos dos mapas de origem, mas isso não acontece mais porque as pessoas pediam para removê-los.

Outros arquivos

Em outras ocasiões, você pode encontrar outros arquivos / pastas indesejados:

  • ./out-tsc/
    De ./src/tsconfig.json'soutDir
  • ./out-tsc-e2e/
    De ./e2e/tsconfig.json'soutDir
  • ./dist/ngfactory/
    Do compilador AoT (não configurável sem bifurcar a CLI a partir da versão 16)
Meligy
fonte
É possível separar a lib angular e suas dependências do meu aplicativo?
Dominick Piganell
Não usar a CLI, que é intencional para que a trepidação de árvores funcione. Isso está removendo todos os módulos Angular EcmaScript que não são usados ​​no seu aplicativo. Há um plano para desativar isso no modo dev para velocidade (eles chamam as bibliotecas carregadas como são "DLL"), mas nenhum plano para separar no resultado final. Deve ser possível se você estiver lançando seu próprio material Webpack sem a CLI.
Melissy
Como verificar meu aplicativo usando a pasta dist. Como posso hospedar no meu servidor web?
raj m 27/01
Você acabou de copiá-lo para o servidor. É um site estático simples que pode ser exibido de qualquer maneira. Se você usar o roteamento, convém redirecionar todas as chamadas para o arquivo HTML. Para isso, verifique os documentos de implantação Angular na seção de configuração do servidor angular.io/docs/ts/latest/guide/…
Meligy
@ Meligy e se eu remover <content-hash>os pacotes no prod. pode causar problemas na obtenção do pacote mais recente?
K11k2
5

Até hoje, ainda encontro o livro de receitas de Compilação antecipada como a melhor receita para agrupar a produção. Você pode encontrá-lo aqui: https://angular.io/docs/ts/latest/cookbook/aot-compiler.html

Minha experiência com o Angular 2 até agora é que o AoT cria as versões menores, quase sem tempo de carregamento. E o mais importante, como é a pergunta aqui - você só precisa enviar alguns arquivos para produção.

Isso ocorre porque o compilador Angular não será enviado com as compilações de produção, pois os modelos são compilados "Antecipadamente". Também é muito bacana ver sua marcação de modelo HTML transformada em instruções javascript que seriam muito difíceis de fazer a engenharia reversa no HTML original.

Fiz um vídeo simples em que demonstro o tamanho do download, o número de arquivos, etc., para um aplicativo Angular 2 em compilação dev vs AoT - que você pode ver aqui:

https://youtu.be/ZoZDCgQwnmQ

Você encontrará o código-fonte usado no vídeo aqui:

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

Peter Salomonsen
fonte
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.
Tushar Tibude
fonte
2

Você pode implantar seu aplicativo angular githubusando angular angular-cli-ghpages

confira o link para descobrir como implantar usando este CLI.

o site implantado será armazenado em alguma filial da github normalmente

páginas gh

O uso pode clonar o ramo git e usá-lo como um site estático no seu servidor

Sunil Kumar
fonte
1

"Melhor" depende do cenário. Há momentos em que você se preocupa apenas com o menor pacote único possível, mas em aplicativos grandes, pode ser necessário considerar um carregamento lento. Em algum momento, torna-se impraticável veicular o aplicativo inteiro como um único pacote.

Neste último caso, o Webpack é geralmente a melhor maneira, pois suporta a divisão de código.

Para um único pacote, consideraria o Rollup ou o compilador Closure se você estiver se sentindo corajoso :-)

Criei amostras de todos os empacotadores angulares que já usei aqui: http://www.syntaxsuccess.com/viewarticle/angular-production-builds

O código pode ser encontrado aqui: https://github.com/thelgevold/angular-2-samples

Versão angular: 4.1.x

TGH
fonte
0

Basta configurar o angular 4 com o webpack 3 em um minuto, seu pacote ENV de desenvolvimento e produção ficará pronto sem nenhum problema, basta seguir o documento abaixo do github

https://github.com/roshan3133/angular2-webpack-starter

AniketGole
fonte
0

Por favor, tente abaixo do comando da CLI no diretório do projeto atual. Isso criará um pacote de pastas dist. para que você possa carregar todos os arquivos na pasta dist para implantações.

ng build --prod --aot --base-href.

Nagnath Mungade
fonte
0

ng serve obras para atender nosso aplicativo para fins de desenvolvimento. E quanto à produção? Se olharmos para o nosso arquivo package.json, podemos ver que existem scripts que podemos usar:

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

O script de construção usa a construção ng da CLI Angular com o sinalizador --prod. Vamos tentar isso agora. Podemos fazer isso de duas maneiras:

# usando os scripts npm

npm run build

# usando o cli diretamente

ng build --prod

Desta vez, recebemos quatro arquivos em vez dos cinco. O sinalizador --prod informa ao Angular para tornar nosso aplicativo muito menor em tamanho.

yogesh waghmare
fonte