I am using Angular2 with SystemJS which worked quite well during development. Now I wanted to deploy my first compiled version using gulp.
To clarify, I use the following systemJS file:
(function(global) {
// map tells the System loader where to look for things
var map = {
'app': 'app', // 'dist',
'rxjs': 'lib/node_modules/rxjs',
'angular2-in-memory-web-api': 'lib/node_modules/angular2-in-memory-web-api',
'@angular': 'lib/node_modules/@angular',
'ng2-charts/bundles': 'lib/node_modules/ng2-charts/bundles',
'ng2-charts/components': 'lib/node_modules/ng2-charts/components',
'ng2-cookies': 'lib/node_modules/ng2-cookies/'
};
// packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { format: 'register', defaultExtension: 'js' },
'rxjs': { defaultExtension: 'js' },
'angular2-in-memory-web-api': { 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',
];
// add package entries for angular packages in the form '@angular/common': { main: 'index.js', defaultExtension: 'js' }
packageNames.forEach(function(pkgName) {
packages[pkgName] = { main: 'index.js', defaultExtension: 'js' };
});
var config = {
baseURL: "/",
defaultJSExtension : true,
map: map,
packages: packages
}
// filterSystemConfig - index.html's chance to modify config before we register it.
if (global.filterSystemConfig) { global.filterSystemConfig(config); }
System.config(config);
})(this);
And the following gulpfile:
const gulp = require('gulp');
const del = require('del');
const typescript = require('gulp-typescript');
const tscConfig = require('./tsconfig.json');
const tsconfig = require('tsconfig-glob');
const sourcemaps = require('gulp-sourcemaps');
// clean the contents of the distribution directory
gulp.task('clean', function () {
return del('dist/**/*');
});
// TypeScript compile
gulp.task('compile', ['clean'], function () {
return gulp
.src(tscConfig.files)
.pipe(sourcemaps.init()) // <--- sourcemaps
.pipe(typescript(tscConfig.compilerOptions))
.pipe(sourcemaps.write('.')) // <--- sourcemaps
.pipe(gulp.dest('dist'));
});
// copy dependencies
gulp.task('copy:libs', ['clean'], function() {
return gulp.src([
'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/router.dev.js',
'node_modules/chart.js/dist/Chart.bundle.min.js',
'node_modules/es6-shim/es6-shim.min.js',
'node_modules/zone.js/dist/zone.js',
'node_modules/reflect-metadata/Reflect.js',
'node_modules/systemjs/dist/system.src.js',
'TcAdsWebService.js'
])
.pipe(gulp.dest('dist/lib'))
});
gulp.task('copy:modules',['clean'],function() {
return gulp.src([
'./node_modules/@angular/**/*',
'./node_modules/rxjs/**/**',
'./node_modules/angular2-in-memory-web-api/**/*',
'./node_modules/ng2-charts/**/*',
'./node_modules/ng2-cookies/**/*'
],{base:'./'}).pipe(gulp.dest('dist/lib'));
});
gulp.task('copy:pics',['clean'], function () {
return gulp.src(['pics/**/*'],{base:'./'}).pipe(gulp.dest('dist/css'));
})
gulp.task('copy:css',['clean'],function() {
return gulp.src(['css/**/*'],{base:'./'}).pipe(gulp.dest('dist/css'));
});
gulp.task('copy:js',['clean'],function() {
return gulp.src(['js/**/*'],{base:'./'}).pipe(gulp.dest('dist/js'));
});
gulp.task('copy:systemJS',['clean'],function() {
return gulp.src(['systemjs.config.js']).pipe(gulp.dest('dist'));
});
// copy static assets - i.e. non TypeScript compiled source
gulp.task('copy:assets', ['clean'], function() {
return gulp.src(['app/**/*', 'index.html', 'styles.css', '!app/**/*.ts'], { base : './' })
.pipe(gulp.dest('dist'))
});
gulp.task('tsconfig-glob', function () {
return tsconfig({
configPath: '.',
indent: 2
});
});
gulp.task('build', ['tsconfig-glob','compile', 'copy:pics', 'copy:js', 'copy:css', 'copy:systemJS','copy:modules','copy:libs', 'copy:assets']);
gulp.task('default', ['build']);
After building the angular2 app and loading it in the browser i get the following error in the console:
Unable to load script http://localhost:81/app/app.component
which indicates, that it is missing the .js extension from the compiled files. I am fairly sure, that
'app': { format: 'register', defaultExtension: 'js' },
should actually require the compiler to mind the .js extension in the app folder, however it doesn't. This is my first angular2 project and my first gulp compile and I am pretty sure I am missing some basic aspect of it but I can't find it in my code.
Given your setup, you should be using systemjs-builder to bundle your app for production. It accepts your SystemJS configuration so further configuration isn't necessary. It bundles your modules into one file, with options to minify, mangle, etc.
This is doing things the "es6 module" way, making better use of our module loader instead of copy/pasting modules like we would do in a traditional javascript app (es5).
Doing this, we can take the dynamic loading out of the index page and just use a script tag pointed at the bundle, it should drastically speed up load times and minimize what the user has to download to load your page. Copying node_modules shouldn't be needed either.
Given a folder structure:
src
|-- app
| |-- main.ts
| |-- index.html
| |-- bundle.min.js
|-- system.config.js
|-- node_modules
|-- tsconfig.json
You can even do all of this with one gulp task.
Task: (requires yargs):
var SystemBuilder = require('systemjs-builder');
var argv = require('yargs').argv;
var builder = new SystemBuilder();
gulp.task('bundle', function () {
builder.loadConfig('./system.config.js')
.then(function () {
var outputFile = argv.prod ? './src/app/bundle.min.js' : './src/app/bundle.js';
return builder.buildStatic('app', outputFile, {
minify: argv.prod,
mangle: argv.prod,
rollup: argv.prod
});
})
.then(function () {
console.log('bundle built successfully!');
});
});
Run this task:
gulp bundle
or
gulp bundle --prod
index.html:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<base href="/" />
<title>Your App</title>
<link rel="stylesheet" href='styles/bootstrap.min.css' />
<script src="/bundle.js"></script>
</head>
<body>
<your-root-component>
</your-root-component>
</body>
</html>
system.config.js:
(function (global) {
var config = {
compiler: "typescript",
map: {
'jquery': 'node_modules/jquery/dist',
'bootstrap': 'node_modules/bootstrap/dist/js',
"reflect-metadata": "node_modules/reflect-metadata",
"zone": "node_modules/zone.js/dist",
"crypto": "node_modules/crypto",
'rxjs': 'node_modules/rxjs',
'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
'@angular': 'node_modules/@angular',
'moment': 'node_modules/moment',
'angular2-moment': 'node_modules/angular2-moment',
'app': 'src/app',
},
meta: {
'node_modules/bootstrap/dist/js/bootstrap.js': {
format: 'global',
deps: ['jquery']
}
},
packages: {
'jquery': { main: 'jquery.js', defaultExtension: 'js' },
'bootstrap': { main: 'bootstrap.js', defaultExtension: 'js' },
'zone': { main: 'zone.js', defaultExtension: 'js' },
'reflect-metadata': { main: 'Reflect.js', defaultExtension: 'js' },
'crypto': { main: 'sha1.js', defaultExtension: 'js' },
'rxjs': { main: 'Rx.js', defaultExtension: 'js' },
'moment':{main: 'moment.js', defaultExtension: 'js'},
'angular2-moment': { main: 'index.js', defaultExtension: 'js' },
'app': { main: 'main.js', 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/testing': { main: 'index.js', defaultExtension: 'js' },
'@angular/upgrade': { main: 'index.js', defaultExtension: 'js' },
'@angular/forms': { main: 'index.js', defaultExtension: 'js' },
}
}
System.config(config);
})(this);
With all of that said: I believe your packages section:
var packages = {
'app': { format: 'register', defaultExtension: 'js' },
'rxjs': { defaultExtension: 'js' },
'angular2-in-memory-web-api': { defaultExtension: 'js' }
};
should be:
var packages = {
'app': { main: 'main.js', defaultExtension: 'js' },
'rxjs': { main: 'Rx.js', defaultExtension: 'js' },
'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' }
};
main.js being whatever file contains your bootstrap function for angular2.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With