Làm cách nào để thực sự triển khai ứng dụng Angular 2 + Typescript + systemjs?


103

Có một hướng dẫn nhanh chóng thông minh hơn tại angle.io, sử dụng các typecript & systemjs. Bây giờ tôi đã có ứng dụng nhỏ đó đang chạy, tôi sẽ tạo ra thứ gì đó có thể triển khai được? Tôi không thể tìm thấy bất kỳ thông tin nào về nó.

Tôi có cần bất kỳ công cụ bổ sung nào, bất kỳ cài đặt bổ sung nào trong System.config không?

(Tôi biết rằng tôi có thể sử dụng webpack và tạo một gói.js duy nhất, nhưng tôi muốn sử dụng systemjs như nó được sử dụng trong hướng dẫn)

Ai đó có thể chia sẻ quy trình xây dựng của họ với thiết lập này không (Angular 2, TypeScript, systemjs)


Đây là công thức của tôi để xây dựng một ứng dụng ng2 để triển khai bằng JSPM: stackoverflow.com/a/34616199/3532945
brando

2
đơn giản câu trả lời ng build -prod stackoverflow.com/a/38421680/5079380
Amr ElAdawy

Câu trả lời:


66

Điều quan trọng cần hiểu ở cấp độ này là sử dụng cấu hình sau, bạn không thể nối trực tiếp các tệp JS đã biên dịch.

Tại cấu hình trình biên dịch TypeScript:

{
  "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"
  ]
}

Trong HTML

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

Trên thực tế, các tệp JS này sẽ chứa các mô-đun ẩn danh. Mô-đun ẩn danh là một tệp JS sử dụng System.registernhưng không có tên mô-đun làm tham số đầu tiên. Đây là những gì trình biên dịch typecript tạo ra theo mặc định khi systemjs được định cấu hình làm trình quản lý mô-đun.

Vì vậy, để có tất cả các mô-đun của bạn vào một tệp JS duy nhất, bạn cần tận dụng thuộc outFiletính trong cấu hình trình biên dịch TypeScript của mình.

Bạn có thể sử dụng bên trong gulp sau để làm điều đó:

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'));
});

Điều này có thể được kết hợp với một số xử lý khác:

  • để xác minh những thứ mà các tệp TypeScript đã biên dịch
  • để tạo một app.jstệp
  • để tạo vendor.jstệp cho thư viện bên thứ ba
  • để tạo một boot.jstệp để nhập mô-đun khởi động ứng dụng. Tệp này phải được bao gồm ở cuối trang (khi tất cả trang được tải).
  • cập nhật index.htmlđể tính đến hai tệp này

Các phụ thuộc sau được sử dụng trong các tác vụ gulp:

  • gulp-concat
  • gulp-html-Replace
  • gulp-stylescript
  • nuốt nước bọt-uglify

Sau đây là một mẫu để nó có thể được điều chỉnh.

  • Tạo app.min.jstệp

    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'));
    });
  • Tạo vendors.min.jstệp

    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'));
    });
  • Tạo boot.min.jstệp

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

    Đơn config.prod.jsgiản chỉ chứa những điều sau:

     System.import('boot')
        .then(null, console.error.bind(console));
  • Cập nhật index.htmltệp

    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'));
    });

    Các index.htmlngoại hình như sau:

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

Lưu ý rằng System.import('boot');phải thực hiện ở cuối phần nội dung để đợi tất cả các thành phần ứng dụng của bạn được đăng ký từ app.min.jstệp.

Tôi không mô tả ở đây cách xử lý CSS và HTML minification.


1
bạn có thể tạo một repo github với một ví dụ được không?
jdelobel

Tôi đã làm theo hướng dẫn của bạn và tất cả đều có vẻ ổn liên quan đến việc nuốt nước bọt. Tuy nhiên, khi tôi chạy ứng dụng trong trình duyệt, tôi gặp lỗi nhật ký bảng điều khiển này: "system.src.js: 1625 Uncaught TypeError: Nhiều lệnh gọi System.register ẩn danh trong cùng một tệp mô-đun." Bất kỳ ý tưởng điều này có nghĩa là gì và làm thế nào để sửa chữa nó?
AngularM

@AngularM: bạn có tham số outFile không? Đây là chìa khóa cho lỗi của bạn ;-)
Thierry Templier

Tôi có nó trong tệp gulp của mình và tsconfig
AngularM

Bạn có thể xem qua dự án github mà tôi đã gửi không? Xem bình luận của tôi ở trên. Bạn có thấy một số khác biệt với mã của bạn?
Thierry Templier

28

Bạn có thể sử dụng lệnh xây dựng angle2-cli

ng build -prod

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

Các bản dựng được tạo bằng cờ -prod thông qua ng build -prodhoặc ng serve -prodgói tất cả các phần phụ thuộc vào một tệp duy nhất và sử dụng kỹ thuật rung cây .

Cập nhật

Câu trả lời này đã được gửi khi angle2 ở trong rc4

Tôi đã thử lại trên phiên bản angle-cli beta21 và angle2 ^ 2.1.0 và nó đang hoạt động như mong đợi

Câu trả lời này yêu cầu khởi tạo ứng dụng bằng angle-cli mà bạn có thể sử dụng

ng new myApp

Hoặc trên một cái hiện có

ng init

Cập nhật 08/06/2018

Đối với góc 6 thì cú pháp khác.

ng build --prod --build-optimizer

Kiểm tra tài liệu


8
Điều này yêu cầu ứng dụng của bạn phải được cấu trúc theo cấu trúc theo ý kiến ​​của angle-cli.
Michael Pell

2
@Amr ElAdawy FYI angle-cli đã chuyển sang webpack. Câu hỏi này có liên quan đến SystemJS. ng xây dựng không làm việc cho tôi.
Shahriar Hasan Sayeed

@ShahriarHasanSayeed Bạn đang đề cập đến thời gian tôi gửi câu trả lời hay thời gian bạn thử nó?
Amr ElAdawy

@AmrElAdawy, bạn có thể thêm phiên bản cho các mô-đun nơi điều này thực sự hoạt động không. Angular2 đã thay đổi khá nhiều kể từ tháng 7.
ppovoski

2
Việc chuyển đổi hướng dẫn Tour of Heroes sang phiên bản cli là điều tầm thường. Chỉ cần tạo một dự án mới bằng cli và sau đó sao chép các tệp hướng dẫn qua.
Rosdi Kasim

12

Bạn có thể xây dựng một dự án Angular 2 (2.0.0-rc.1) trong Typescript bằng SystemJS với GulpSystemJS-Builder .

Dưới đây là phiên bản đơn giản về cách xây dựng, gói và thu nhỏ Tour of Heroes chạy 2.0.0-rc.1 ( nguồn đầy đủ , ví dụ trực tiếp ).

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
});


2
Bạn có thể vui lòng chỉ rõ, làm thế nào để chạy SystemJs và Gulp?
Jan Drozen

@JanDrozen Ở cùng vị trí với gulpfile của bạn, bạn có thể chạy gulp <taskname>trong đó "taskname" là tên của tác vụ gọi trình tạo SystemJS, trong ví dụ trên của tôi là như vậy bundle:app. Trong tác vụ Gulp đó, bạn có thể sử dụng mô-đun npm 'systemjs-builder' để chỉ định cấu hình Hệ thống và tệp ngoài của bạn.
Steely

@ steely: Cảm ơn! Hoạt động như một sự quyến rũ. Mong đợi mục tiêu mặc định - phương thức uglify () bị thiếu (hoặc tôi thiếu thứ gì đó). Bạn có thể giải thích cho tôi phần cuối cùng chưa rõ ràng này được không?
Jan Drozen,

@Steely bạn vui lòng hướng dẫn cách thực hiện với phiên bản mới hơn của angle2?
micronyks

@ Steely. bạn có thể cung cấp liên kết cuối cùng (trên github) của các tệp xây dựng angle2 mới nhất được yêu cầu để chạy ứng dụng khởi động nhanh angle2 không?
micronyks

1

Đây là bảng soạn sẵn MEA2N của tôi cho Angular 2: https://github.com/simonxca/mean2-boilerplate

Đó là một tấm boilerplate đơn giản dùng tscđể ghép mọi thứ lại với nhau. (Thực ra sử dụng grunt-ts , cốt lõi của nó chỉ là tsclệnh.) Không cần Wekpack, v.v.

Cho dù bạn có sử dụng grunt hay không, ý tưởng là:

  • viết ứng dụng của bạn trong một thư mục có tên ts/(ví dụ public/ts/:)
  • sử dụng tscđể sao chép cấu trúc ts/thư mục của thư mục của bạn vào một js/thư mục và chỉ các tệp tham chiếu trong js/thư mục của bạn index.html.

Để grunt-ts hoạt động (phải có một lệnh tương đương cho tsc đơn giản, Gulp, v.v.), bạn có một thuộc tính trong tsconfig.jsonđược gọi của bạn "outDir": "../js"và tham chiếu nó trong gruntfile.jsvới:

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

Sau đó, chạy grunt ts, thao tác này sẽ đưa ứng dụng của bạn vào public/ts/và phản chiếu ứng dụng đó public/js/.

Đây. Siêu dễ hiểu. Không phải là cách tiếp cận tốt nhất, nhưng là cách tốt để bắt đầu.


1

Cách dễ nhất mà tôi đã tìm thấy để gói rc1 góc cho systemJs là sử dụng gulpsystemjs-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);
        });
});

Như đã chỉ ra trong các nhận xét, systemJs hiện gặp vấn đề khi đóng gói các thành phần bằng cách sử dụng moduleId: module.id

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

Đề xuất hiện tại (góc 2 rc1) dường như sử dụng các đường dẫn rõ ràng, tức là moduleId: '/app/path/'


Điều này có vẻ hứa hẹn nhưng nó không thành công khi tôi sử dụng các đường dẫn tương đối đến các mẫu bên ngoài trong trình @Componenttrang trí. bundle.jscố gắng giải quyết các đường dẫn là tuyệt đối mặc dù chúng tương đối, gây ra lỗi 404 (xem stackoverflow.com/questions/37497635/… ). Bạn đã đối phó với điều đó như thế nào?
BeetleJuice

bạn đang thiết lập moduleIdđường dẫn tương đối?
paul

Không chắc là tôi hiểu. Tôi có moduleId: module.idtrong@Component
BeetleJuice

Điều đó có những hạn chế tương tự như đặt xuống con đường đầy đủ templateUrlvà đánh bại mục đích có moduleIdngay từ đầu. Tôi đang cố gắng sử dụng các đường dẫn tương đối như được khuyến nghị ( angle.io/docs/ts/latest/cookbook/… )
BeetleJuice

bạn có thể gặp nhiều may mắn hơn bằng cách tự mình moduleId: '/app/components/home/'
vạch


0

Trong trang web Angular.io, trong phần Nâng cao / Triển khai, khuyến nghị rằng cách đơn giản nhất để triển khai là 'sao chép môi trường phát triển vào máy chủ'.

  1. xem qua phần bên dưới: Triển khai đơn giản nhất có thể. Các tệp dự án cuối cùng được hiển thị bên trong phần mã. Lưu ý rằng nó đã thiết lập mã để tải các tệp gói npm từ web (thay vì từ thư mục npm_modules cục bộ).

  2. đảm bảo rằng nó đang chạy trên máy tính cục bộ của bạn (npm start). Sau đó, trong thư mục dự án, sao chép mọi thứ trong thư mục con '/ src' vào nhóm S3 mà bạn đã thiết lập. Bạn có thể sử dụng tính năng kéo và thả để sao chép, trong quá trình đó, bạn sẽ có tùy chọn để chọn cài đặt quyền cho các tệp, đảm bảo rằng chúng 'có thể đọc được' đối với 'mọi người'.

  3. trong tab 'Thuộc tính' của nhóm, hãy tìm bảng điều khiển 'Lưu trữ trang web tĩnh', chọn tùy chọn 'Sử dụng nhóm này để lưu trữ trang web' và chỉ định 'index.html' cho cả tài liệu Chỉ mục và tài liệu Lỗi.

  4. nhấp vào Endpoint trang web tĩnh, dự án của bạn đang chạy tốt!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.