Як я можу реально розгорнути програму Angular 2 + Typescript + systemjs?


103

На angular.io є підручник з швидкого початку роботи, який використовує typecript і systemjs. Тепер, коли у мене працює цей miniapp, як би я почав створювати щось розгортається? Я не міг знайти жодної інформації про це.

Чи потрібні мені додаткові інструменти, додаткові налаштування в System.config?

(Я знаю, що я можу використовувати webpack і створити єдиний bundle.js, але я хотів би використовувати systemjs, як він використовується в підручнику)

Чи може хтось поділитися своїм процесом збирання з цією установкою (Angular 2, TypeScript, systemjs)


Ось мій рецепт для створення додатка NG2 для розгортання з допомогою JSPM: stackoverflow.com/a/34616199/3532945
Брандо

2
Проста відповідь Ng збірки -prod stackoverflow.com/a/38421680/5079380
Амр 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але без назви модуля, як перший параметр. Це те, що компілятор машинопису генерується за замовчуванням, коли 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-substitute
  • gulp-typecript
  • ковтати-зливати

Далі наведено зразок, щоб його можна було адаптувати.

  • Створити 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

Я маю це у своєму файлі gulp та tsconfig
AngularM

Не могли б ви ознайомитись із проектом, який я представив? Дивіться мій коментар вище. Ви бачите якісь відмінності у своєму коді?
Тьеррі Темплієр

28

Ви можете скористатися командою збірки angular2-cli

ng build -prod

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

Створює, створений прапором -prod, через ng build -prodабо поєднуючиng serve -prod всі залежності в один файл , і використовує методи струшування дерева .

Оновлення

Ця відповідь була подана, коли angular2 був у rc4

Я спробував його ще раз на antal-cli beta21 та angular2 ^ 2.1.0, і він працює як слід

Ця відповідь вимагає ініціалізації програми з кутовим кліпом, який ви можете використовувати

ng new myApp

Або на існуючому

ng init

Оновлення 06.06.2018

Для кутових 6 синтаксис відрізняється.

ng build --prod --build-optimizer

Перевірте документацію


8
Це вимагає, щоб ваш додаток було структуровано у виразній структурі кутового кліпу.
Майкл Пелл

2
@Amr ElAdawy FYI angular-cli перейшов до веб-пакету. Це питання стосується SystemJS. Набір для мене не працює.
Шахріар Хасан Сайєд

@ShahriarHasanSayeed Ви маєте на увазі час, коли я подав відповідь, або час, коли ви його спробували?
Amr ElAdawy

@AmrElAdawy, чи можете ви додати версії для модулів, де це насправді працює. Angular2 досить змінився з липня.
ppovoski

2
Перетворити підручник «Тур Героїв» у версію cli нерівно. Просто генеруйте новий проект за допомогою cli, а потім скопіюйте файли підручника.
Росді Касім

12

Ви можете побудувати проект Angular 2 (2.0.0-rc.1) у Typescript за допомогою SystemJS з Gulp та SystemJS-Builder .

Нижче представлена ​​спрощена версія, як створити, згрупувати та мінімізувати Tour of Heroes, що працює на версії 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?
Jan Drozen

@JanDrozen У тому самому місці, де і ваш gulpfile, ви можете запустити, gulp <taskname>де "ім'я завдання" - це ім'я завдання, яке викликає конструктора SystemJS, у моєму вище прикладі це bundle:app. У цьому завданні Gulp ви можете використовувати npm-модуль 'systemjs-builder' для вказівки вашої конфігурації системи та виходу з файлу.
Стілі

@ steely: Дякую! Працює як шарм. Очікуйте ціль за замовчуванням - метод uglify () відсутній (або я щось пропускаю). Чи можете ви поясніть мені цю останню незрозумілу частину?
Jan Drozen

@Steely, підкажіть, будь ласка, як це зробити з новою версією angular2?
мікроніки

@ Steely.can ви надаєте остаточне посилання (на github) останніх файлів збірки angular2, необхідних для запуску angular2 quickstart-app?
мікроніки

1

Ось моя котла MEA2N для кутових 2: https://github.com/simonxca/mean2-boilerplate

Це проста котельня, яка використовується tscдля складання речей. ( На насправді використовує рубаки-TS , яка за своєю суттю є тільки tscкоманда.) Немає Wekpack і т.п. необхідно.

Незалежно від того, використовуєте ви грунтування чи ні, ідея полягає в наступному:

  • написати додаток у папку під назвою ts/(приклад public/ts/:)
  • використовувати tscдля дзеркального відображення структури каталогів вашої ts/папки в js/папку та просто довідкові файли в js/папці у вашій index.html.

Щоб заставити grunt-t працювати (повинна бути еквівалентна команда для звичайного tsc, Gulp тощо), ви маєте властивість у своєму tsconfig.jsonвиклику "outDir": "../js"та посилаєте його на свій gruntfile.js:

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

Потім запустіть grunt ts, який увійде ваш додаток public/ts/і відобразить його в дзеркалі public/js/.

Там. Супер легко зрозуміти. Не найкращий підхід, але хороший для початку.


1

Найпростіший спосіб, який я знайшов, щоб зв'язати кутовий 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/isissue/6131

Поточна рекомендація (кутова 2 rc1), здається, використовує явні шляхи, тобто moduleId: '/app/path/'


Це здається багатообіцяючим, але воно виходить з ладу, коли я використовую відносні шляхи до зовнішніх шаблонів у @Componentдекораторі. bundle.jsнамагається вирішити шляхи як абсолютні, хоча вони відносні, викликаючи 404 помилки (див. stackoverflow.com/questions/37497635/… ). Як ви з цим впоралися?
Жук-джуйс

ви встановлюєте moduleIdвідносний шлях?
Павло

Не впевнений, що розумію. Я маю moduleId: module.idв@Component
Beetlejuice

Це має ті ж недоліки, що і відкладення повного шляху, templateUrlі перемагає мету moduleIdв першу чергу. Я намагаюся використовувати відносні шляхи, як рекомендовано ( angular.io/docs/ts/latest/cookbook/… )
BeetleJuice

ви можете мати більше удачі, явно вказавши шлях самостійно , наприкладmoduleId: '/app/components/home/'
PAUL


0

На веб-сайті Angular.io, в розділі Розширений / Розгортання, рекомендується, щоб найпростішим способом розгортання є "копіювання середовища розробки на сервер".

  1. пройдіть розділ у розділі: Найпростіший варіант розгортання. Кінцеві файли проекту показані всередині кодового розділу. Зауважте, що він вже встановлює код для завантаження файлів пакетів npm з Інтернету (замість локальної папки npm_modules).

  2. переконайтеся, що він працює на вашому локальному комп’ютері (npm start). Потім в папку проекту скопіюйте все, що знаходиться в підпапці '/ src', у відтворене вами S3. Ви можете використовувати перетягування для копіювання, під час цього процесу ви отримуєте можливість вибору налаштувань дозволу для файлів, переконайтеся, що вони є "читабельними" для "всіх".

  3. на вкладці "Властивості", відвідайте панель "Статичний хостинг веб-сайтів", поставте прапорець "Використовувати це відро для розміщення веб-сайту" та вкажіть "index.html" як для документа, так і для документа про помилку.

  4. натисніть на статичний кінцевий веб-сайт, ваш проект добре працює!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.