Как подготовить релизную версию с помощью SystemJS и Gulp?

Я использую SystemJS в своем проекте Angular2. Я использую файл tsconfig для TypeScript. Я хочу использовать gulp для объединения и минимизации моего кода для производственной версии. У меня проблемы с объединением кода: каждый раз, когда я пытаюсь объединить файлы, я получаю либо «угловой», либо не определенный «системный». Я попытался изменить порядок, в котором я пытаюсь загрузить свои файлы из узловых модулей, однако мне это не удалось.

Мне было интересно, есть ли у кого-нибудь из вас эта проблема, и нашел ли на нее ответ?

Вот мой файл глотка:

var gulp = require('gulp'),
            .....


var paths = {
    dist: 'dist',
    vendor: {
        js: [
            'node_modules/systemjs/dist/system.src.js',
            'node_modules/angular2/bundles/angular2.dev.js',
            'node_modules/angular2/bundles/angular2-polyfills.js',
            'node_modules/angular2/bundles/router.dev.js'
             ...
        ],
        css: []
},
    app: {
        templates: [
            'app/**/*.html',
            '!node_modules/*.html'
        ],
        scripts: [
            'app/**/*.ts',
            'app/config.ts',
            'app/app.ts'
        ]
    }
};

var tsProject = ts.createProject('tsconfig.json', {
    out: 'Whatever.js'
});

gulp.task('dev:build:templates', function () {
    return gulp.src(paths.app.templates)
        .pipe(ngHtml2Js({
            moduleName: 'Whatever',
            declareModule: false
        }))
        .pipe(concat("Whatever.tpls.min.js"))
        .pipe(gulp.dest(paths.dist));
});
gulp.task('prod:build:templates', function () {
    return gulp.src(paths.app.templates)
        .pipe(minifyHtml({
            empty: true,
            spare: true,
            quotes: true
        }))
        .pipe(ngHtml2Js({
            moduleName: 'whatever',
            declareModule: false
        }))
        .pipe(concat(paths.appName + ".tpls.min.js"))
        .pipe(uglify())
        .pipe(gulp.dest(paths.dist));
});

gulp.task('dev:build:scripts', function () {
    var tsResult = tsProject.src()
        .pipe(sourcemaps.init())
        .pipe(ts(tsProject));

    return tsResult.js
        .pipe(sourcemaps.write({
            sourceRoot: '/app'
        }))
        .pipe(concat('whatever.js'))
        .pipe(gulp.dest(paths.dist));
});

gulp.task('dev:build:styles', function () {
    return gulp.src(paths.app.styles)
        .pipe(sass())
        .pipe(gulp.dest(paths.dist + '/css'));
});
gulp.task('dev:build:vendor', function () {
    return gulp.src(paths.vendor.js)
        .pipe(concat('vendor.min.js'))
        .pipe(gulp.dest(paths.dist))
});

gulp.task('dev:build', [
    'dev:build:vendor',
    'dev:build:templates',
    'dev:build:scripts',
    'dev:build:styles',
], function () {
});

Вот как я загружаю свои файлы:

   <script src="vendor.min.js"></script>
   <script src="Whatever.js"></script>
   <script src="Whatever.tpls.min.js"></script>

И вот ошибки, которые я получаю:

Uncaught TypeError: Unexpected anonymous System.register call.(anonymous function) @ vendor.min.js:2680load.metadata.format @ vendor.min.js:3220oldModule @ vendor.min.js:3749(anonymous function) @ vendor.min.js:2411SystemJSLoader.register @ vendor.min.js:2636(anonymous function) @ Whatever.js:2
Whatever.tpls.min.js:1 Uncaught ReferenceError: angular is not defined

person uksz    schedule 05.01.2016    source источник
comment
См. Должны ли вопросы включать «теги» в свои заголовки? , где консенсуса нет, не должны!   -  person    schedule 05.01.2016
comment
@AndreasNiedermair, извини, не понял, что   -  person uksz    schedule 05.01.2016
comment
обмен частью вашего кода также поможет найти вашу проблему.   -  person toskv    schedule 05.01.2016
comment
@toskv, какая часть кода вас интересует? файл глотка? структура моих файлов после задач gulp?   -  person uksz    schedule 05.01.2016
comment
gulp файл и файловая структура были бы хорошим началом. :)   -  person toskv    schedule 05.01.2016
comment
Конечно, я отредактирую свой вопрос сейчас   -  person uksz    schedule 05.01.2016
comment
Убедитесь, что вы сначала загрузили angular и systemjs.   -  person maxisam    schedule 05.01.2016
comment
@maxisam именно это я и делаю. Все равно выдает ошибку   -  person uksz    schedule 05.01.2016
comment
Что ж, проверьте консоль браузера и посмотрите, действительно ли вы указываете правильный путь.   -  person maxisam    schedule 05.01.2016
comment
@toskv, я загрузил свой глоток   -  person uksz    schedule 05.01.2016
comment
@maxisam, все файлы есть, и действительно, кажется, что все указывает в правильном направлении   -  person uksz    schedule 05.01.2016
comment
я бы не связывал их как vendor.js. Попробуйте загрузить их по отдельности и посмотрите, правильно ли вы загружаете их.   -  person maxisam    schedule 05.01.2016
comment
@maxisam, это действительно работает, когда я их не связываю (в моей версии для разработки). Тем не менее, для выпуска я хотел бы связать их. Порядок, который я использую для разработки, такой же, как и порядок их загрузки в gulp, так что это не должно влиять на проект, верно?   -  person uksz    schedule 05.01.2016
comment
Порядок выглядит нормально, но проверьте выходной файл и убедитесь, что он соответствует вашим ожиданиям.   -  person maxisam    schedule 05.01.2016
comment
Кстати, я думаю, что angular2-polyfills.js должен загружаться первым, но на самом деле это не ваша проблема.   -  person maxisam    schedule 05.01.2016
comment
Компилятор TypeScript не выводит имена ваших модулей, поэтому вам придется полагаться на имена файлов, чтобы получить имена модулей. Если вы объедините файлы вместе, у вас просто будет куча анонимных модулей в файле, который SystemJs не знает, когда загружать. Я считаю, что вам нужно использовать инструмент сборки SystemJs, если вы хотите связать свои файлы github.com/systemjs/builder . Однако мне никогда не удавалось успешно заставить его работать.   -  person rob    schedule 05.01.2016


Ответы (3)


Вы получите «Неожиданный анонимный вызов System.register», потому что ссылки не загружаются в правильном порядке. Я использую JSPM для правильной сборки моего углового приложения для производства. Процесс состоит из 4 частей.

Часть 1. Скомпилируйте файлы машинописного текста

var ts = require("gulp-typescript");
var tsProject = ts.createProject("./App/tsconfig.json");
gulp.task("compile:ts", function () {
    var tsResult = tsProject.src()
        .pipe(ts(tsProject));
    tsResult.js.pipe(gulp.dest("./wwwroot/app"));

});

Часть 2. Настройте config.js (чтобы указать JSPM, как связать ваше приложение):

System.config({
  baseURL: "/",
  defaultJSExtensions: true,
  paths: {
    "npm:*": "jspm_packages/npm/*",
    "github:*": "jspm_packages/github/*",
    "node_modules*": "node_modules/*"
  },
  map: {
    'app': 'app',
    'rxjs': 'node_modules/rxjs',
    '@angular': 'node_modules/@angular'
  },
  packages: {
    'app': { main: 'bootDesktop.js', defaultExtension: 'js' },
    'rxjs': { defaultExtension: 'js' },
    '@angular/common': { main: 'index.js', defaultExtension: 'js' },
    '@angular/compiler': { main: 'index.js', defaultExtension: 'js' },
    '@angular/core': { main: 'index.js', defaultExtension: 'js' },
    '@angular/http': { main: 'index.js', defaultExtension: 'js' },
    '@angular/platform-browser': { main: 'index.js', defaultExtension: 'js' },
    '@angular/platform-browser-dynamic': { main: 'index.js', defaultExtension: 'js' },
    '@angular/router': { main: 'index.js', defaultExtension: 'js' },
    '@angular/router-deprecated': { main: 'index.js', defaultExtension: 'js' },
    '@angular/testing': { main: 'index.js', defaultExtension: 'js' },
    '@angular/upgrade': { main: 'index.js', defaultExtension: 'js' }
  }


});

Часть 3. Используйте gulp-jspm-build для объединения вашего приложения (ранее я использовал gulp-jspm, но это вызывало ошибки, поэтому я переключился на gulp-jspm-build):

var jspm = require('gulp-jspm-build');
gulp.task("jspm_bundle", function () {
return jspm({
    bundleOptions: {
        minify: true,
        mangle: false
    },
    bundleSfx: true,
    bundles: [
        { src: './wwwroot/app/appBoot.js', dst: 'boot.bundle.min.js' }
    ]
})
.pipe(gulp.dest('./wwwroot/js-temp'));


});
//this will create a file called boot.bundle.min.js
//note I have set jspm to create a self-executing bundle
//I put mangle to false because mangling was causing errors 

4: Теперь объедините все ваши уже минифицированные активы:

gulp.task("min:js", ["jspm_bundle"], function () {
    //this only concats boot.bundle.min.js
    //and dependencies.min.js which has already been minified such as es6-shim.js
    var files = [
        "./wwwroot/js-temp/dependencies.min.js",
        "./wwwroot/js-temp/boot.bundle.min.js"
    ];

    return gulp.src(files)
        .pipe(concat("boot.bundle.min.js"))
        .pipe(gulp.dest("./wwwroot/js"));

});

Наконец, поместите одну симпатичную аккуратную ссылку на скрипт в свой index.html:

<script src="~/js/boot.bundle.min.js"> </script>
One of the nice features of this approach is that your bundled app will only contain the assets that are actually referenced in you import statements (jspm won't bundle it if you don't need it).

ОБНОВЛЕНИЕ: Пересмотренный config.js для соответствия приложению Angular 2.0-rc.0

ОБНОВЛЕНИЕ 2: tsconfig.json выглядит так:

{
  "compilerOptions": {
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "module": "commonjs",
    "moduleResolution": "node",
    "noImplicitAny": false,
    "noEmitOnError": true,
    "removeComments": false,
    "sourceMap": true,
    "declaration": false,
    "noLib": false,
    "target": "es5",
    "outDir": "wwwroot/app/"
  },
  "exclude": [
    "node_modules",
    "wwwroot"
  ]
}

person brando    schedule 05.01.2016
comment
Спасибо! Я попробую это через пару часов, так как я сейчас в афк - person uksz; 05.01.2016
comment
Пожалуйста. Самым сложным было выяснить аргументы карты в файле config.json. Вам не нужно снова импортировать jspm angular2, просто укажите, что уже находится в папке node_modules. - person brando; 05.01.2016
comment
@brando Я думаю, что это должен быть config.js вместо config.json. - person pharfe; 06.02.2016
comment
@brando Вы оставляете angular2 в качестве зависимости от npm, чтобы компилятор машинописного текста мог его найти? По этой причине я изо всех сил пытался заставить jspm работать. - person reblace; 01.05.2016
comment
@reblace да, я оставляю angular2 как зависимость от npm. но когда вы связываетесь с jspm (по крайней мере, в моем подходе), angular УЖЕ транспилируется в js, поэтому jspm не беспокоится о машинописном тексте (хотя jspm cli также может справиться с этой задачей). В файле config.js вы сообщаете jspm, где эта зависимость (и другие) находится в вашей файловой структуре и какие типы файлов вы связываете (например, js или ts). - person brando; 01.05.2016
comment
теперь я использую gulp-jspm-build вместо gulp-jspm, который выдавал ошибки. Ответ обновлен - person brando; 01.05.2016
comment
@brando, поскольку вопрос привлекает так много внимания, не могли бы вы обеспечить поддержку метаданных отражения? когда я пытаюсь следовать руководству, моя консоль регистрирует «Неперехваченная прокладка метаданных отражения требуется при использовании декораторов классов» - person uksz; 09.06.2016
comment
привет @uksz, вам нужно включить Reflect.js как часть пакета dependencies.min.js, как указано на шаге 4. - person brando; 09.06.2016
comment
@brando: Не могли бы вы опубликовать, как выглядит ваш tsconfig.json? - person Pankaj Kapare; 09.09.2016
comment
@PankajKapare Я разместил файл tsconfig.json - person brando; 10.09.2016
comment
@brando: Спасибо. Я успешно реализовал сборку. Очень помогло. - person Pankaj Kapare; 10.09.2016
comment
Я использовал import().then(function(module){module.init()}) для инициализации компонентов при их загрузке. Но когда я связываю компонент (не одно большое приложение, один пакет на страницу), а затем делаю то же самое, я получаю сообщение об ошибке, что init() не является функцией. Как люди инициализируют модули, когда они загружаются? - person James White; 18.10.2016

Вы можете использовать SystemJS Builder.

так просто, как это

var path = require("path");
var Builder = require('systemjs-builder');

// optional constructor options
// sets the baseURL and loads the configuration file
var builder = new Builder('path/to/baseURL', 'path/to/system/config-file.js');

builder
.bundle('local/module.js', 'outfile.js')
.then(function() {
  console.log('Build complete');
})
.catch(function(err) {
  console.log('Build error');
  console.log(err);
});

вы можете посмотреть полную настройку в моем начальном проекте

person Antony Budianto    schedule 07.05.2016
comment
Приведенный выше пример должен использоваться вместе с SystemJS, так как ему все еще нужен загрузчик. Если вы предпочитаете отдельный пакет, используйте .buildStatic и поместите пакет в тег скрипта. - person Antony Budianto; 11.05.2016
comment
Энтони Будианто, я попробовал ваш стартовый проект для создания проекта angular 2 rc 4. когда я изменил некоторое содержимое, я не смог создать файл сборки из-за какой-то ошибки/неудачного теста. Если вы можете предоставить базовый скелет процесса сборки / начального проекта с самыми базовыми функциями, такими как без тестовых примеров ... очень очень базовый скелет, который поможет мне учиться у основ. Angular 2 они предоставили наполовину сваренный процесс сборки веб-пакета. Пока я ищу помощь в получении процесса сборки для angular 2 rc4, я узнал, что у многих людей есть такие же проблемы. Пожалуйста, помогите нам - person Jose G Varanam; 02.08.2016
comment
Энтони Будианто, это запрос, который я разместил на stackoverflow.com/questions/38610209/ - person Jose G Varanam; 02.08.2016
comment
Итак, каким должен быть путь для вызова System.import в подобном сценарии? Это путь к outfile.js? - person chrismarx; 27.09.2016

Думаю, мы нашли основную причину этого. Честно говоря, я был там раньше, поэтому то, как я отслеживаю этот тип проблемы,

  1. Проверьте, загружены ли angular и systemjs заранее.
  2. Проверьте, действительно ли они загружены. нет 404 сюрприз. (Звучит глупо, но дерьмо случается)
  3. Если вы связываете библиотеки как vender.js, убедитесь, что они собраны в правильной последовательности. Проверьте выходной файл и посмотрите, совпадают ли они, как вы ожидаете.
person maxisam    schedule 05.01.2016