I'm putting together an app (Large scale) using Angular2 and TypeScript. It will need to be divided into numerous projects and each project will have numerous components each with a .html
view, .css
stylesheet and .ts
logic / class.
I would like each project to compile to a single *.js
file and be copied to a host website which will run in IIS. This would be similar to how a WPF or Silverlight app is built with the .xaml
files all getting compiled into the .dll
.
I've had a look around the web and am able to get the .ts
files to build to a single .js
file using the --outFile
option. But this doesn't help me with the .html
files or the css
.
Any help would be greatly appreciated even if it's to say that what I'm asking is impossible :-)
Stephen
If you're using the default Angular2 tsconfig.json
with SystemJS loader:
"module": "system",
"moduleResolution": "node",
...
You can leave all the heavy work on SystemJS Build Tool. This is for example how I do it in my projects using gulp
:
Compile *.ts and inline *.html templates
I'm using gulp-angular-embed-templates
right away to inline all templateUrl
into template
strings (this plugin works with both Angular 1.* and Angular 2).
var tsc = require('gulp-typescript');
var tsProject = tsc.createProject('tsconfig.json');
var embedTemplates = require('gulp-angular-embed-templates');
gulp.task('app.build', function () {
var tsResult = gulp.src('app/src/**/*.ts', {base: './app/src'})
.pipe(embedTemplates()) // inline templates
.pipe(tsc(tsProject));
return tsResult.js
.pipe(gulp.dest('build/js'));
});
This will generate many anonymous System.register modules in build/js
directory. All of them will have their templateUrl
inlined already.
Bundle everything into a single .js
file
I use SystemJS Build Tool for this because I think it's way easier than using for example webpack. So, I have another gulp task for this to automate the process:
var SystemBuilder = require('systemjs-builder');
gulp.task('app.systemjs.bundle', function () {
var builder = new SystemBuilder('build/js, {
paths: {
'*': '*.js'
},
meta: {
'angular2/*': {
build: false
},
'rxjs/*': {
build: false
}
}
});
return builder.bundle('main', 'build/js/app.bundle.js');
});
The builder takes the same options as SystemJS so check their Config API.
Calling builder.bundle('main', ...)
searches for main.js
(which is my initial script with Angular's bootstrap
call. It's the same file you can see in the 5 min quickstart) because I append .js
to all paths searched by the builder. This is because when you import a module in TS you usually call:
import {ModalResultComponent} from './modal-result.component';
which is compiled as ./modal-result.component
dependency and it doesn't care about the file extension. That's why I had to add *.js
to all paths to help builder find all compiled JavaScript files.
The meta
options just tell the builder to ignore dependencies that I don't want to bundle. That's Angular2 itself and rxjs
library because I include import 'rxjs/add/operator/map'
in main.ts
.
This generates a single app.bundle.js
file with all modules registered as named modules using System.register.
Using our app.bundle.js
The last part is a piece of cake. We just import the default Angular2 stuff and then use bundle
option to tell SystemJS where're all our dependencies.
<script>
System.config({
packages: {
'/web': {
format: 'register',
defaultExtension: 'js'
}
},
bundles: {
'/web/app.bundle': ['main']
}
});
System.import('main').then(null, console.error.bind(console));
</script>
When we call System.import('main')
it in fact first downloads /web/app.bundle.js
and registers all modules in the package and after that it imports modules main
with our Angular2 bootstrap.
And that's it!
You actually don't need to use gulp
at all and do everything with pure node
script.
Bundling CSS files is easy with things like cssnano and I'm sure you can find tutorials on how to use it everywhere.
I'm sure there're other ways to the the same thing. Angular2 is designed not to restrict you to use just one technology. However, using SystemJS seems to me to be the easiest way because it uses the same module system as Angular2 by default.
I'm sure you could use also for example commonjs
format but that would require you to use also some polyfill for require()
loader, but I haven't tried it yet. I belive UMD might be also worth trying.