איך אני באמת מפרסם אפליקציה של Angular 2 + Typescript + systemjs?
יש מדריך התחלה מהירה באתר angular.io שמשתמש ב-Typescript ו-SystemJS. עכשיו כששידרגתי את המיני-אפליקציה הזו, איך אני יכול ליצור משהו שניתן לפרוס? לא הצלחתי למצוא שום מידע על זה אפילו.
האם אני צריך כלים נוספים כלשהם, הגדרות נוספות ב-System.config?
(אני יודע שאני יכול להשתמש ב-webpack וליצור קובץ bundle.js יחיד, אבל אני רוצה להשתמש ב-systemjs כפי שמשתמשים בו במדריך)
מישהו יכול לשתף את תהליך הבנייה שלו עם ההגדרה הזו (Angular 2, TypeScript, systemjs)
תשובה #1
הדבר החשוב להבין ברמה זו הוא שבעזרת התצורה הבאה, לא ניתן לצרף ישירות קבצי 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 שלך.
אתה יכול להשתמש בדבר הבא בתוך gulp כדי לעשות זאת:
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-replace
- גאלפ-טייפסקריפט
- גלופ-אגליף
להלן דוגמה כך שניתן להתאים אותה.
צור קובץ
app.min.jsgulp.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.jsgulp.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.jsgulp.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.htmlgulp.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'); חייב להתבצע בסוף ה-body כדי להמתין שכל רכיבי האפליקציה שלך יירשמו מהקובץ app.min.js.
אני לא מתאר כאן את הדרך לטפל במיניפיקציה של CSS ו-HTML.
תשובה #2
אתה יכול להשתמש בפקודה angular2-cli build
ng build -prod
https://github.com/angular/angular-cli/wiki/build#bundling
בניינים שנוצרו עם הדגל -prod דרך
ng build -prodאוng serve -prodאוספים את כל התלויות ל-קובץ יחיד, ומשתמשים בטכניקות tree-shaking.
עדכון
תשובה זו נשלחה כאשר Angular2 היה ב-rc4
ניסיתי את זה שוב על angular-cli beta21 ו-angular2 ^2.1.0 וזה עובד כפי שציפיתי
תשובה זו מחייבת אתחול של האפליקציה עם angular-cli שניתן להשתמש בו
ng new myApp
או על אחד קיים
ng init
עדכון 08/06/2018
ל-angular 6 התחביר שונה.
ng build --prod --build-optimizer
בדוק את התיעוד
תשובה #3
אתה יכול לבנות פרויקט 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
});