Wie stelle ich eine Angular 2 + Typescript + systemjs-App bereit?

103

Unter angular.io gibt es ein Schnellstart-Tutorial, das Typoskript und Systemjs verwendet. Wie würde ich nach dem Ausführen dieser Miniapp vorgehen, um etwas Bereitstellbares zu erstellen? Ich konnte überhaupt keine Informationen darüber finden.

Benötige ich zusätzliche Tools und zusätzliche Einstellungen in System.config?

(Ich weiß, dass ich webpack verwenden und ein einzelnes bundle.js erstellen kann, aber ich möchte systemjs verwenden, wie es im Tutorial verwendet wird.)

Könnte jemand seinen Erstellungsprozess mit diesem Setup teilen (Angular 2, TypeScript, systemjs)

Brian G. Bell
quelle
Hier ist mein Rezept zum Erstellen einer ng2-App für die Bereitstellung mit JSPM: stackoverflow.com/a/34616199/3532945
brando
2
einfache Antwort ng build -prod stackoverflow.com/a/38421680/5079380
Amr ElAdawy

Antworten:

66

Auf dieser Ebene ist es wichtig zu verstehen, dass Sie mit der folgenden Konfiguration kompilierte JS-Dateien nicht direkt zusammenfassen können.

Bei der TypeScript-Compilerkonfiguration:

{
  "compilerOptions": {
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "declaration": false,
    "stripInternal": true,
    "module": "system",
    "moduleResolution": "node",
    "noEmitOnError": false,
    "rootDir": ".",
    "inlineSourceMap": true,
    "inlineSources": true,
    "target": "es5"
  },
  "exclude": [
    "node_modules"
  ]
}

Im HTML

System.config({
  packages: {
    app: {
      defaultExtension: 'js',
      format: 'register'
    }
  }
});

Tatsächlich enthalten diese JS-Dateien anonyme Module. Ein anonymes Modul ist eine JS-Datei, die System.registerjedoch ohne den Modulnamen als ersten Parameter verwendet wird. Dies generiert der Typoskript-Compiler standardmäßig, wenn systemjs als Modulmanager konfiguriert ist.

Um alle Ihre Module in einer einzigen JS-Datei zu haben, müssen Sie die outFileEigenschaft in Ihrer TypeScript-Compilerkonfiguration nutzen.

Sie können das folgende innere Schlucken verwenden, um das zu tun:

const gulp = require('gulp');
const ts = require('gulp-typescript');

var tsProject = ts.createProject('tsconfig.json', {
  typescript: require('typescript'),
  outFile: 'app.js'
});

gulp.task('tscompile', function () {
  var tsResult = gulp.src('./app/**/*.ts')
                     .pipe(ts(tsProject));

  return tsResult.js.pipe(gulp.dest('./dist'));
});

Dies könnte mit einer anderen Verarbeitung kombiniert werden:

  • um die kompilierten TypeScript-Dateien zu hässlich zu machen
  • um eine app.jsDatei zu erstellen
  • um eine vendor.jsDatei für Bibliotheken von Drittanbietern zu erstellen
  • um eine boot.jsDatei zum Importieren des Moduls zu erstellen , das die Anwendung bootstrap. Diese Datei muss am Ende der Seite enthalten sein (wenn die gesamte Seite geladen ist).
  • um das zu aktualisieren index.html, um diese beiden Dateien zu berücksichtigen

Die folgenden Abhängigkeiten werden in den Schluckaufgaben verwendet:

  • Schluck-Concat
  • gulp-html-replace
  • Schluck-Typoskript
  • schlucken-hässlich machen

Das Folgende ist ein Beispiel, damit es angepasst werden kann.

  • app.min.jsDatei erstellen

    gulp.task('app-bundle', function () {
      var tsProject = ts.createProject('tsconfig.json', {
        typescript: require('typescript'),
        outFile: 'app.js'
      });
    
      var tsResult = gulp.src('app/**/*.ts')
                       .pipe(ts(tsProject));
    
      return tsResult.js.pipe(concat('app.min.js'))
                    .pipe(uglify())
                    .pipe(gulp.dest('./dist'));
    });
  • vendors.min.jsDatei erstellen

    gulp.task('vendor-bundle', function() {
      gulp.src([
        'node_modules/es6-shim/es6-shim.min.js',
        'node_modules/systemjs/dist/system-polyfills.js',
        'node_modules/angular2/bundles/angular2-polyfills.js',
        'node_modules/systemjs/dist/system.src.js',
        'node_modules/rxjs/bundles/Rx.js',
        'node_modules/angular2/bundles/angular2.dev.js',
        'node_modules/angular2/bundles/http.dev.js'
      ])
      .pipe(concat('vendors.min.js'))
      .pipe(uglify())
      .pipe(gulp.dest('./dist'));
    });
  • boot.min.jsDatei erstellen

    gulp.task('boot-bundle', function() {
      gulp.src('config.prod.js')
        .pipe(concat('boot.min.js'))
        .pipe(uglify())
        .pipe(gulp.dest('./dist'));
     });

    Das config.prod.jsenthält einfach folgendes:

     System.import('boot')
        .then(null, console.error.bind(console));
  • Aktualisieren Sie die index.htmlDatei

    gulp.task('html', function() {
      gulp.src('index.html')
        .pipe(htmlreplace({
          'vendor': 'vendors.min.js',
          'app': 'app.min.js',
          'boot': 'boot.min.js'
        }))
        .pipe(gulp.dest('dist'));
    });

    Das index.htmlsieht wie folgt aus:

    <html>
      <head>
        <!-- Some CSS -->
    
        <!-- build:vendor -->
        <script src="node_modules/es6-shim/es6-shim.min.js"></script>
        <script src="node_modules/systemjs/dist/system-polyfills.js"></script>
        <script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
        <script src="node_modules/systemjs/dist/system.src.js"></script>
        <script src="node_modules/rxjs/bundles/Rx.js"></script>
        <script src="node_modules/angular2/bundles/angular2.dev.js"></script>
        <script src="node_modules/angular2/bundles/http.dev.js"></script>
        <!-- endbuild -->
    
        <!-- build:app -->
        <script src="config.js"></script>
        <!-- endbuild -->
      </head>
    
      <body>
        <my-app>Loading...</my-app>
    
        <!-- build:boot -->
        <!-- endbuild -->
      </body>
    </html>

Beachten Sie, dass System.import('boot');dies am Ende des Körpers erfolgen muss, um darauf zu warten, dass alle Ihre App-Komponenten aus der app.min.jsDatei registriert werden.

Ich beschreibe hier nicht den Umgang mit CSS- und HTML-Minimierung.

Thierry Templier
quelle
1
Kannst du bitte ein Github-Repo mit einem Beispiel erstellen?
jdelobel
Ich habe Ihre Anweisungen befolgt und alles sieht gut aus in Bezug auf Schlucken. Wenn ich die App jedoch im Browser ausführe, wird der folgende Konsolenprotokollfehler angezeigt: "system.src.js: 1625 Nicht erfasster Typfehler: Mehrere anonyme System.register-Aufrufe in derselben Moduldatei." Irgendwelche Ideen, was dies bedeutet und wie man es behebt?
AngularM
@ AngularM: Haben Sie den Parameter outFile? Dies ist der Schlüssel für Ihren Fehler ;-)
Thierry Templier
Ich habe es in meiner Schluckdatei und tsconfig
AngularM
Könnten Sie sich das von mir eingereichte Github-Projekt ansehen? Siehe meinen Kommentar oben. Sehen Sie einige Unterschiede zu Ihrem Code?
Thierry Templier
28

Sie können den Build-Befehl angle2-cli verwenden

ng build -prod

https://github.com/angular/angular-cli/wiki/build#bundling

Mit dem Flag -prod erstellte Builds erstellenng build -prod oder ng serve -prodbündeln alle Abhängigkeiten in einer einzigen Datei und verwenden Tree-Shaking- Techniken.

Aktualisieren

Diese Antwort wurde übermittelt, als angle2 in rc4 war

Ich hatte es erneut mit Angular-Cli Beta21 und Angular2 ^ 2.1.0 versucht und es funktioniert wie erwartet

Diese Antwort erfordert die Initialisierung der App mit Angular-Cli, die Sie verwenden können

ng new myApp

Oder auf einem bestehenden

ng init

Update 08/06/2018

Für Winkel 6 ist die Syntax unterschiedlich.

ng build --prod --build-optimizer

Überprüfen Sie die Dokumentation

Amr ElAdawy
quelle
8
Dies setzt voraus, dass Ihre App in der Meinungsstruktur von angle-cli strukturiert ist.
Michael Pell
2
@Amr ElAdawy FYI Angular-Cli wechselte zu Webpack. Diese Frage bezieht sich auf SystemJS. ng build funktioniert bei mir nicht.
Shahriar Hasan Sayeed
@ShahriarHasanSayeed Beziehen Sie sich auf die Zeit, zu der ich die Antwort eingereicht habe, oder auf die Zeit, als Sie es versucht haben?
Amr ElAdawy
@AmrElAdawy, können Sie die Versionen für die Module hinzufügen, in denen dies tatsächlich funktioniert. Angular2 hat sich seit Juli ziemlich verändert.
ppovoski
2
Es ist trivial, das Tour of Heroes-Tutorial in die Cli-Version zu konvertieren. Generieren Sie einfach ein neues Projekt mit cli und kopieren Sie die Tutorial-Dateien.
Rosdi Kasim
12

Sie können ein Angular 2-Projekt (2.0.0-rc.1) in Typescript mit SystemJS mit Gulp und SystemJS-Builder erstellen .

Im Folgenden finden Sie eine vereinfachte Version zum Erstellen, Bündeln und Minimieren von Tour of Heroes mit 2.0.0-rc.1 ( vollständige Quelle , Live-Beispiel ).

gulpfile.js

var gulp = require('gulp');
var sourcemaps = require('gulp-sourcemaps');
var concat = require('gulp-concat');
var typescript = require('gulp-typescript');
var systemjsBuilder = require('systemjs-builder');

// Compile TypeScript app to JS
gulp.task('compile:ts', function () {
  return gulp
    .src([
        "src/**/*.ts",
        "typings/*.d.ts"
    ])
    .pipe(sourcemaps.init())
    .pipe(typescript({
        "module": "system",
        "moduleResolution": "node",
        "outDir": "app",
        "target": "ES5"
    }))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('app'));
});

// Generate systemjs-based bundle (app/app.js)
gulp.task('bundle:app', function() {
  var builder = new systemjsBuilder('public', './system.config.js');
  return builder.buildStatic('app', 'app/app.js');
});

// Copy and bundle dependencies into one file (vendor/vendors.js)
// system.config.js can also bundled for convenience
gulp.task('bundle:vendor', function () {
    return gulp.src([
        'node_modules/jquery/dist/jquery.min.js',
        'node_modules/bootstrap/dist/js/bootstrap.min.js',
        'node_modules/es6-shim/es6-shim.min.js',
        'node_modules/es6-promise/dist/es6-promise.min.js',
        'node_modules/zone.js/dist/zone.js',
        'node_modules/reflect-metadata/Reflect.js',
        'node_modules/systemjs/dist/system-polyfills.js',
        'node_modules/systemjs/dist/system.src.js',
      ])
        .pipe(concat('vendors.js'))
        .pipe(gulp.dest('vendor'));
});

// Copy dependencies loaded through SystemJS into dir from node_modules
gulp.task('copy:vendor', function () {
  gulp.src(['node_modules/rxjs/**/*'])
    .pipe(gulp.dest('public/lib/js/rxjs'));

  gulp.src(['node_modules/angular2-in-memory-web-api/**/*'])
    .pipe(gulp.dest('public/lib/js/angular2-in-memory-web-api'));
  
  return gulp.src(['node_modules/@angular/**/*'])
    .pipe(gulp.dest('public/lib/js/@angular'));
});

gulp.task('vendor', ['bundle:vendor', 'copy:vendor']);
gulp.task('app', ['compile:ts', 'bundle:app']);

// Bundle dependencies and app into one file (app.bundle.js)
gulp.task('bundle', ['vendor', 'app'], function () {
    return gulp.src([
        'app/app.js',
        'vendor/vendors.js'
        ])
    .pipe(concat('app.bundle.js'))
    .pipe(uglify())
    .pipe(gulp.dest('./app'));
});

gulp.task('default', ['bundle']);

system.config.js

var map = {
  'app':                                'app',
  'rxjs':                               'vendor/rxjs',
  'zonejs':                             'vendor/zone.js',
  'reflect-metadata':                   'vendor/reflect-metadata',
  '@angular':                           'vendor/@angular'
};

var packages = {
  'app':                                { main: 'main', defaultExtension: 'js' },
  'rxjs':                               { defaultExtension: 'js' },
  'zonejs':                             { main: 'zone', defaultExtension: 'js' },
  'reflect-metadata':                   { main: 'Reflect', defaultExtension: 'js' }
};

var packageNames = [
  '@angular/common',
  '@angular/compiler',
  '@angular/core',
  '@angular/http',
  '@angular/platform-browser',
  '@angular/platform-browser-dynamic',
  '@angular/router',
  '@angular/router-deprecated',
  '@angular/testing',
  '@angular/upgrade',
];

packageNames.forEach(function(pkgName) {
  packages[pkgName] = { main: 'index.js', defaultExtension: 'js' };
});

System.config({
  map: map,
  packages: packages
});

Steely
quelle
2
Könnten Sie bitte angeben, wie SystemJs und Gulp ausgeführt werden sollen?
Jan Drozen
@JanDrozen Am selben Speicherort wie Ihre Gulpfile können Sie ausführen, gulp <taskname>wobei "Aufgabenname" der Name der Aufgabe ist, die den SystemJS-Builder aufruft. In meinem obigen Beispiel ist dies der Fall bundle:app. In dieser Gulp-Aufgabe können Sie das npm-Modul 'systemjs-builder' verwenden, um Ihre Systemkonfiguration und Outfile anzugeben.
Steely
@ steely: Danke! Klappt wunderbar. Erwarten Sie das Standardziel - die uglify () -Methode fehlt (oder mir fehlt etwas). Können Sie mir bitte diesen letzten unklaren Teil erklären?
Jan Drozen
@Steely würden Sie bitte führen, wie es mit neueren Version von angle2 geht?
Mikronyken
@ Steely.Kannst du einen endgültigen Link (auf Github) der neuesten Angular2-Build-Dateien bereitstellen, die zum Ausführen der Angular2-Schnellstart-App erforderlich sind?
Mikronyken
1

Hier ist meine MEA2N-Boilerplate für Angular 2: https://github.com/simonxca/mean2-boilerplate

Es ist eine einfache Boilerplate, mit tscder Dinge zusammengesetzt werden. (Verwendet tatsächlich grunt-ts , was im Kern nur der tscBefehl ist.) Kein Wekpack usw. erforderlich.

Ob Sie Grunzen verwenden oder nicht, die Idee ist:

  • schreiben Sie Ihre App in einem Ordner namens ts/(Beispiel: public/ts/)
  • Verwenden Sie tscdiese Option, um die Verzeichnisstruktur Ihres ts/Ordners in einen js/Ordner zu spiegeln und nur auf Dateien in dem js/Ordner in Ihrem Ordner zu verweisen index.html.

Damit grunt-ts funktionieren (es sollte einen äquivalenten Befehl für einfaches tsc, Gulp usw. geben), haben Sie eine Eigenschaft in Ihrem tsconfig.jsonAufruf "outDir": "../js"und verweisen in Ihrer gruntfile.jsmit:

grunt.initConfig({
  ts: {
    source: {tsconfig: 'app/ts/tsconfig.json'}
  },
  ...
});

Führen Sie dann aus grunt ts, wodurch Ihre App aufgenommen public/ts/und gespiegelt wird public/js/.

Dort. Super leicht zu verstehen. Nicht der beste Ansatz, aber ein guter, um loszulegen.

Simonxca
quelle
1

Der einfachste Weg, den ich gefunden habe, um den Winkel rc1 für systemJs zu bündeln, ist zu verwenden gulpund systemjs-builder:

gulp.task('bundle', function () {
    var path = require('path');
    var Builder = require('systemjs-builder');

    var builder = new Builder('/node_modules');

    return builder.bundle([
        '@angular/**/*.js'
        ], 
        'wwwroot/bundle.js', 
        { minify: false, sourceMaps: false })
        .then(function () {
            console.log('Build complete');
        })
        .catch(function (err) {
            console.log('Build error');
            console.log(err);
        });
});

Wie in den Kommentaren erwähnt, hat systemJs derzeit Probleme beim Bündeln von Komponenten mit moduleId: module.id

https://github.com/angular/angular/issues/6131

Die aktuelle Empfehlung (Winkel 2 rc1) scheint darin zu bestehen, explizite Pfade zu verwenden, d. H. moduleId: '/app/path/'

paul
quelle
Dies scheint vielversprechend, schlägt jedoch fehl, wenn ich relative Pfade zu externen Vorlagen im @ComponentDekorator verwende. bundle.jsversucht, Pfade als absolut aufzulösen, obwohl sie relativ sind, was 404 Fehler verursacht (siehe stackoverflow.com/questions/37497635/… ). Wie sind Sie damit umgegangen?
BeetleJuice
Stellen Sie moduleIdden relativen Pfad ein?
Paul
Nicht sicher ob ich verstehe. Ich habe moduleId: module.idin@Component
BeetleJuice
Das hat die gleichen Nachteile, als würde man den vollen Weg beschreiten templateUrlund den Zweck, überhaupt etwas zu haben, moduleIdzunichte machen. Ich versuche, relative Pfade wie empfohlen zu verwenden ( angle.io/docs/ts/latest/cookbook/… )
BeetleJuice
Sie können mehr Glück haben, indem Sie den Pfad explizit selbst moduleId: '/app/components/home/'
festlegen,
0

Auf der Angular.io-Website im Abschnitt "Erweitert / Bereitstellung" wird empfohlen, dass die einfachste Art der Bereitstellung darin besteht, die Entwicklungsumgebung auf den Server zu kopieren.

  1. Lesen Sie den Abschnitt unter: Einfachste Bereitstellung möglich. Die endgültigen Projektdateien werden im Codeabschnitt angezeigt. Beachten Sie, dass der Code zum Laden von npm-Paketdateien aus dem Web bereits eingerichtet ist (anstelle des lokalen Ordners npm_modules).

  2. Stellen Sie sicher, dass es auf Ihrem lokalen Computer ausgeführt wird (npm start). Kopieren Sie dann unter dem Projektordner alles im Unterordner '/ src' in den von Ihnen eingerichteten S3-Bucket. Sie können per Drag & Drop kopieren. Während dieses Vorgangs haben Sie die Möglichkeit, die Berechtigungseinstellung für die Dateien auszuwählen und sicherzustellen, dass sie für "alle" "lesbar" sind.

  3. Suchen Sie auf der Registerkarte "Eigenschaften" des Buckets nach dem Bereich "Statisches Website-Hosting", aktivieren Sie die Option "Mit diesem Bucket die Website hosten" und geben Sie "index.html" sowohl für das Indexdokument als auch für das Fehlerdokument an.

  4. Klicken Sie auf die statische Website Endpoint, Ihr Projekt läuft gut!

Joseph Wu
quelle