ฉันจะปรับใช้แอพ Angular 2 + typescript + systemjs ได้อย่างไร


103

มีบทช่วยสอนที่รวดเร็วกว่าที่ angular.io ซึ่งใช้ typescript & systemjs ตอนนี้ฉันมีแอป miniapp ที่ทำงานอยู่ฉันจะสร้างสิ่งที่ใช้งานได้อย่างไร ฉันไม่พบข้อมูลใด ๆ เกี่ยวกับเรื่องนี้เลย

ฉันต้องการเครื่องมือพิเศษใด ๆ การตั้งค่าเพิ่มเติมใน System.config หรือไม่?

(ฉันรู้ว่าฉันสามารถใช้ webpack และสร้าง bundle.js เดียวได้ แต่ฉันต้องการใช้ systemjs ตามที่ใช้ในบทช่วยสอน)

มีใครสามารถแบ่งปันขั้นตอนการสร้างของพวกเขาด้วยการตั้งค่านี้ (Angular 2, TypeScript, systemjs)


นี่คือสูตรของฉันในการสร้างแอป ng2 สำหรับการปรับใช้โดยใช้ JSPM: stackoverflow.com/a/34616199/3532945
brando

2
คำตอบง่ายๆ ng build -prod stackoverflow.com/a/38421680/5079380
Amr ElAdawy

คำตอบ:


66

สิ่งสำคัญที่ต้องเข้าใจในระดับนี้คือการใช้การกำหนดค่าต่อไปนี้คุณไม่สามารถเชื่อมต่อไฟล์ JS ที่คอมไพล์ได้โดยตรง

ที่คอนฟิกูเรชันคอมไพเลอร์ 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"
  ]
}

ใน HTML

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

ตามความเป็นจริงไฟล์ JS เหล่านี้จะมีโมดูลที่ไม่ระบุชื่อ โมดูลที่ไม่ระบุชื่อคือไฟล์ JS ที่ใช้System.registerแต่ไม่มีชื่อโมดูลเป็นพารามิเตอร์แรก นี่คือสิ่งที่คอมไพลเลอร์ typescript สร้างขึ้นโดยค่าเริ่มต้นเมื่อกำหนดค่า systemjs เป็นตัวจัดการโมดูล

ดังนั้นเพื่อให้โมดูลทั้งหมดของคุณเป็นไฟล์ JS เดียวคุณต้องใช้ประโยชน์จากoutFileคุณสมบัติภายในคอนฟิกูเรชันคอมไพเลอร์ TypeScript ของคุณ

คุณสามารถใช้สิ่งต่อไปนี้ภายในอึกเพื่อทำสิ่งนั้น:

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

สิ่งนี้สามารถใช้ร่วมกับการประมวลผลอื่น ๆ :

  • เพื่ออัปเกรดไฟล์ TypeScript ที่คอมไพล์แล้ว
  • เพื่อสร้างapp.jsไฟล์
  • เพื่อสร้างvendor.jsไฟล์สำหรับไลบรารีของบุคคลที่สาม
  • เพื่อสร้างboot.jsไฟล์เพื่อนำเข้าโมดูลที่บูตแอปพลิเคชัน ต้องรวมไฟล์นี้ไว้ที่ส่วนท้ายของหน้า (เมื่อโหลดหน้าทั้งหมดแล้ว)
  • เพื่ออัปเดตโดยindex.htmlคำนึงถึงสองไฟล์นี้

การอ้างอิงต่อไปนี้ใช้ในงานอึก:

  • อึก - ต่อกัน
  • gulp-html- แทนที่
  • อึกชนิด
  • อึก - อัปลักษณ์

ต่อไปนี้เป็นตัวอย่างเพื่อนำไปปรับใช้

  • สร้างapp.min.jsไฟล์

    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.jsไฟล์

    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.jsไฟล์

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

    config.prod.jsก็มีดังต่อไปนี้:

     System.import('boot')
        .then(null, console.error.bind(console));
    
  • อัปเดตindex.htmlไฟล์

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

    index.htmlลักษณะเช่นต่อไปนี้:

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

สังเกตว่าSystem.import('boot');ต้องทำที่ส่วนท้ายของเนื้อหาเพื่อรอให้ส่วนประกอบแอปทั้งหมดของคุณได้รับการลงทะเบียนจากapp.min.jsไฟล์

ฉันไม่ได้อธิบายถึงวิธีจัดการการลดขนาด CSS และ HTML ที่นี่


1
คุณสามารถสร้าง github repo ด้วยตัวอย่างได้ไหม
jdelobel

ฉันทำตามคำแนะนำของคุณและทุกคนก็ดูดีเกี่ยวกับอึก อย่างไรก็ตามเมื่อฉันเรียกใช้แอปในเบราว์เซอร์ฉันได้รับข้อผิดพลาดในบันทึกของคอนโซล: "system.src.js: 1625 Uncaught TypeError: การเรียก System.register ที่ไม่ระบุชื่อหลายรายการในไฟล์โมดูลเดียวกัน" มีความคิดเห็นว่าสิ่งนี้หมายถึงอะไรและจะแก้ไขได้อย่างไร?
AngularM

@AngularM: คุณมีพารามิเตอร์ outFile หรือไม่? นี่คือกุญแจสำคัญสำหรับข้อผิดพลาดของคุณ ;-)
Thierry Templier

ฉันมีมันอยู่ในไฟล์อึกของฉันและ tsconfig
AngularM

คุณช่วยดูโครงการ github ที่ฉันส่งมาได้ไหม ดูความคิดเห็นของฉันด้านบน คุณเห็นความแตกต่างบางอย่างกับรหัสของคุณหรือไม่?
Thierry Templier

28

คุณสามารถใช้คำสั่งสร้าง angular2-cli

ng build -prod

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

บิลด์ที่สร้างด้วยแฟล็ก -prodผ่านng build -prodหรือng serve -prodรวมการอ้างอิงทั้งหมดไว้ในไฟล์เดียวและใช้เทคนิคการเขย่าต้นไม้

อัปเดต

คำตอบนี้ถูกส่งเมื่อ angular2 อยู่ใน rc4

ฉันได้ลองอีกครั้งกับ angular-cli beta21 และ angular2 ^ 2.1.0 และใช้งานได้ตามที่คาดไว้

คำตอบนี้ต้องการการเริ่มต้นแอปด้วย angular-cli ที่คุณสามารถใช้ได้

ng new myApp

หรือที่มีอยู่

ng init

Update 08/06/2018

สำหรับเชิงมุม 6 ไวยากรณ์จะแตกต่างกัน

ng build --prod --build-optimizer

ตรวจสอบเอกสาร


8
สิ่งนี้ต้องการให้แอปของคุณมีโครงสร้างตามความเห็นของ angular-cli
Michael Pell

2
@Amr ElAdawy FYI angular-cli ย้ายไปที่ webpack คำถามนี้เกี่ยวข้องกับ SystemJS ng build ไม่ได้ผลสำหรับฉัน
Shahriar Hasan Sayeed

@ShahriarHasanSayeed คุณหมายถึงเวลาที่ฉันส่งคำตอบหรือเวลาที่คุณลอง?
Amr ElAdawy

@AmrElAdawy คุณสามารถเพิ่มเวอร์ชันสำหรับโมดูลที่ใช้งานได้จริง Angular2 มีการเปลี่ยนแปลงเล็กน้อยตั้งแต่เดือนกรกฎาคม
ppovoski

2
การแปลงบทช่วยสอน Tour of Heroes เป็นเวอร์ชัน cli เป็นเรื่องเล็กน้อย เพียงสร้างโปรเจ็กต์ใหม่โดยใช้ cli จากนั้นคัดลอกไฟล์การสอน
Rosdi Kasim

12

คุณสามารถสร้างเชิงมุม 2 (2.0.0-rc.1) โครงการใน typescript ใช้ SystemJS กับอึกและSystemJS-Builder

ด้านล่างนี้เป็นรุ่นที่เรียบง่ายของวิธีการสร้างมัดและลดขนาดทัวร์วีรบุรุษทำงาน 2.0.0-rc.1 ( ที่มาเต็ม , ตัวอย่างสด )

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
คุณช่วยระบุวิธีเรียกใช้ SystemJs และ Gulp ได้อย่างไร
ม.ค. Drozen

@JanDrozen ในสถานที่เดียวกับ gulpfile ของคุณคุณสามารถทำงานgulp <taskname>ที่ไหน "TaskName" เป็นชื่อของงานที่เรียกว่าสร้าง SystemJS bundle:appในตัวอย่างข้างต้นของฉันมันเป็น ในงาน Gulp นั้นคุณสามารถใช้โมดูล npm 'systemjs-builder' เพื่อระบุการกำหนดค่าระบบและไฟล์ภายนอกของคุณ
Steely

@ Steely: ขอบคุณ! ใช้งานได้เหมือนมีเสน่ห์ คาดหวังกับเป้าหมายเริ่มต้น - เมธอด uglify () หายไป (หรือฉันขาดบางอย่าง) คุณช่วยอธิบายส่วนที่ไม่ชัดเจนสุดท้ายนี้ให้ฉันฟังได้ไหม
ม.ค. Drozen

@ คุณ Steely ช่วยแนะนำวิธีทำกับ angular2 เวอร์ชันใหม่กว่าได้ไหม
micronyks

@ Steely คุณสามารถให้ลิงค์สุดท้าย (บน github) ของไฟล์บิวด์ angular2 ล่าสุดที่จำเป็นสำหรับการเรียกใช้แอพ angular2 quickstart-app ได้หรือไม่?
micronyks

1

นี่คือต้นแบบ MEA2N ของฉันสำหรับ Angular 2: https://github.com/simonxca/mean2-boilerplate

เป็นเอกสารสำเร็จรูปง่ายๆที่ใช้tscรวมสิ่งต่างๆเข้าด้วยกัน (จริงๆแล้วใช้grunt-tsซึ่งแกนหลักเป็นเพียงtscคำสั่ง) ไม่จำเป็นต้องใช้ Wekpack และอื่น ๆ

ไม่ว่าคุณจะใช้คำรามหรือไม่ก็ตามแนวคิดคือ:

  • เขียนแอปของคุณในโฟลเดอร์ที่เรียกว่าts/(ตัวอย่าง: public/ts/)
  • ใช้tscเพื่อสะท้อนโครงสร้างไดเร็กทอรีของts/โฟลเดอร์ของคุณลงในjs/โฟลเดอร์และเพียงแค่อ้างอิงไฟล์ในjs/โฟลเดอร์ในไฟล์index.html.

เพื่อให้grunt-tsทำงานได้ (ควรมีคำสั่งที่เทียบเท่าสำหรับ tsc ธรรมดา, Gulp ฯลฯ ) คุณมีคุณสมบัติในการtsconfig.jsonเรียกของคุณ"outDir": "../js"และอ้างอิงในของคุณgruntfile.jsด้วย:

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

แล้วรันgrunt tsซึ่งจะใช้แอปของคุณและสะท้อนไปยังpublic/ts/public/js/

ที่นั่น เข้าใจง่ายสุด ๆ ไม่ใช่แนวทางที่ดีที่สุด แต่เป็นแนวทางที่ดีในการเริ่มต้น


1

วิธีที่ง่ายที่สุดที่ฉันพบในการรวม angular rc1 สำหรับ systemJs คือการใช้gulpและ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);
        });
});

ตามที่ระบุไว้ในความคิดเห็นปัจจุบัน systemJs มีปัญหาเมื่อรวมส่วนประกอบโดยใช้ moduleId: module.id

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

คำแนะนำปัจจุบัน (เชิงมุม 2 rc1) ดูเหมือนจะใช้เส้นทางที่ชัดเจนเช่น moduleId: '/app/path/'


ดูเหมือนจะมีแนวโน้มดี แต่ก็ล้มเหลวเมื่อฉันใช้เส้นทางสัมพัทธ์ไปยังเทมเพลตภายนอกใน@Componentมัณฑนากร bundle.jsพยายามแก้ไขพา ธ เป็นค่าสัมบูรณ์แม้ว่าจะสัมพันธ์กันทำให้เกิดข้อผิดพลาด 404 (ดูstackoverflow.com/questions/37497635/… ) คุณจัดการกับเรื่องนี้อย่างไร?
BeetleJuice

คุณตั้งค่าmoduleIdเป็นเส้นทางสัมพัทธ์หรือไม่?
พอล

ไม่แน่ใจว่าฉันเข้าใจ ฉันมีmoduleId: module.idใน@Component
BeetleJuice

นั่นมีข้อเสียเช่นเดียวกับการวางเส้นทางแบบเต็มไว้ข้างใต้templateUrlและเอาชนะจุดประสงค์ของการมีmoduleIdตั้งแต่แรก ฉันพยายามใช้เส้นทางสัมพัทธ์ตามที่แนะนำ ( angular.io/docs/ts/latest/cookbook/… )
BeetleJuice

คุณอาจมีโชคมากขึ้นโดยกำหนดเส้นทางด้วยตัวเองอย่างชัดเจนเช่นmoduleId: '/app/components/home/'
พอล


0

ภายใต้เว็บไซต์ Angular.io ในส่วนขั้นสูง / การปรับใช้ขอแนะนำว่าวิธีที่ง่ายที่สุดในการปรับใช้คือ 'คัดลอกสภาพแวดล้อมการพัฒนาไปยังเซิร์ฟเวอร์'

  1. ไปที่ส่วนภายใต้: การปรับใช้ที่ง่ายที่สุดเป็นไปได้ ไฟล์โครงการสุดท้ายจะแสดงในส่วนรหัส โปรดทราบว่าได้ตั้งค่ารหัสเพื่อโหลดไฟล์แพ็กเกจ npm จากเว็บแล้ว (แทนจากโฟลเดอร์ npm_modules ในเครื่อง)

  2. ตรวจสอบให้แน่ใจว่าทำงานบนคอมพิวเตอร์ในระบบของคุณ (npm start) จากนั้นภายใต้โฟลเดอร์โครงการให้คัดลอกทุกอย่างในโฟลเดอร์ย่อย '/ src' ไปยังที่เก็บข้อมูล S3 ที่คุณตั้งค่าไว้ คุณสามารถใช้การลากแล้วปล่อยเพื่อคัดลอกในระหว่างขั้นตอนนั้นคุณจะได้รับตัวเลือกในการเลือกการตั้งค่าสิทธิ์สำหรับไฟล์ตรวจสอบให้แน่ใจว่าได้กำหนดให้ 'อ่านได้' สำหรับ 'ทุกคน'

  3. ใต้แท็บ 'คุณสมบัติ' ที่เก็บข้อมูลให้มองหาแผง 'การโฮสต์เว็บไซต์แบบคงที่' เลือกตัวเลือก 'ใช้ที่เก็บข้อมูลนี้เพื่อโฮสต์เว็บไซต์' และระบุ 'index.html' ให้กับทั้งเอกสารดัชนีและเอกสารข้อผิดพลาด

  4. คลิกที่ Endpoint ของเว็บไซต์แบบคงที่โครงการของคุณจะทำงานได้ดี!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.