Rein Baarsma
Rein Baarsma

Reputation: 1536

Angular with systemjs and typescript outFile still includes all files separetely too

I'm trying to use the Typescript compiler and the outFile function to bundle my sources into a single file and load that as normal with systemjs.

When I run the tsc command I get a nice bundle.js, which includes my main code. When I load it in the browser (either apache or lite server) the bundle.js gets loaded first as intended and then systemjs kicks in and starts loading all the .js files separately -- main.js, app.component.js, etc etc. There's no errors -- it simply works, but it shouldn't need to load all the seperate .js files..

I've looked hard at a related post (Load combined modular typescript file with SystemJS) but can't seem to find what I'm doing wrong..

index.html

<!doctype html>
<html lang="en">
<head>
  <base href="/">
  <meta charset="UTF-8">
  <title>Solid Timesheet: Time-tracking made easy!</title>

  <link rel="stylesheet" href="css/main.css">

  <script type="text/javascript">
    // temporary hack for enable bootstrap 4
    window.__theme = 'bs4';
  </script>
  <script>

    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
              (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
            m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

    var localhost = document.location.href.match(/^http:\/\/localhost/);
    ga('create', 'UA-18982324-19', localhost ? 'none' : 'auto');
  </script>

  <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/es6/dev/src/testing/shims_for_IE.js"></script>

  <script src="node_modules/angular2/bundles/angular2-polyfills.min.js"></script>
  <script src="node_modules/systemjs/dist/system.js"></script>
  <script src="node_modules/rxjs/bundles/Rx.min.js"></script>

  <script src="node_modules/angular2/bundles/router.min.js"></script>
  <script src="node_modules/angular2/bundles/http.min.js"></script>
  <script src="node_modules/angular2/bundles/angular2.min.js"></script>

  <script src="node_modules/ng2-bootstrap/bundles/ng2-bootstrap.min.js"></script>
  <script src="bundle.js"></script>

  <script>
    System.config({
      packages: {
        app: {
          format: 'register',
          defaultExtension: 'js'
        },
        "ng2-bootstrap": {
          "defaultExtension": "js"
        },
      },
      map: {
        'ng2-bootstrap': 'node_modules/ng2-bootstrap/bundles/',
        moment: 'node_modules/moment/moment.js',
      }
    });
    System.import('app/main')
            .then(null, console.error.bind(console));
  </script>
</head>

<!-- 3. Display the application -->
<body>
<div class="container">
  <my-app>Loading...</my-app>
</div>
</body>

</html>

tsconfig.json

{
  "compilerOptions": {
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "module": "system",
    "removeComments": true,
    "sourceMap": false,
    "noImplicitAny": false,
    "outFile": "bundle.js"
  },
  "exclude": [
    "node_modules",
    "typings"
  ]
}

I'm using typescript 1.8.9

Upvotes: 0

Views: 1805

Answers (2)

Steely
Steely

Reputation: 720

I ran into that problem as well. I was able to bundle my app into one file (e.g. one network request) using outDir (instead of outFile) in my tsconfig and SystemJS-Builder (see full source and live example).

system.config.js

var map = {
  'app':                                'dist/js',
  'rxjs':                               'lib/js/rxjs',
  'angular2-in-memory-web-api':         'lib/js/angular2-in-memory-web-api',
  '@angular':                           'lib/js/@angular'
};

var packages = {
  'app':                                { main: 'main', 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',
];

packageNames.forEach(function(pkgName) {
  packages[pkgName] = { main: 'index.js', defaultExtension: 'js' };
});

System.config({
  map: map,
  packages: packages
});

tsconfig.json

{
  "compilerOptions": {
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "module": "system",
    "moduleResolution": "node",
    "outDir": "public/dist/js",
    "sourceMap": true,
    "target": "ES5"
  },
  "exclude": [
    "node_modules"
  ],
  "filesGlob": [
    "src/**/*.ts",
    "typings/*.d.ts"
  ]
}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <base href="/">
    <title>Hello World</title>
    <meta charset="UTF-8">

    <link rel="stylesheet" href="dist/css/styles.min.css"> <!--compiled global scss styles-->

    <script src="lib/js/vendors.min.js"></script> <!--bundled dependencies-->
    <script src="dist/js/app.min.js"></script> <!--bundled source-->
</head>
<body class="container">
    <my-app>Loading...</my-app>
</body>
</html>

gulpfile.js

A set of tasks which uses tsc to compile, and systemjs-builder to bundle your app.

// Compile TypeScript to JS
gulp.task('compile:ts', function () {
  return gulp
    .src(tscConfig.filesGlob)
    .pipe(sourcemaps.init())
    .pipe(tsc(tscConfig.compilerOptions))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('public/dist'));
});

// Generate systemjs-based builds
gulp.task('bundle:js', function() {
  var builder = new sysBuilder('public', './system.config.js');
  return builder.buildStatic('app', 'public/dist/js/app.min.js');
});

// Minify JS bundle
gulp.task('minify:js', function() {
  return gulp
    .src('public/dist/js/app.min.js')
    .pipe(uglify())
    .pipe(gulp.dest('public/dist/js'));
});

Upvotes: 1

Thierry Templier
Thierry Templier

Reputation: 202216

It's because you need to remove this block from your SystemJS configuration:

System.config({
  packages: {
    app: { // <-----------
      format: 'register',
      defaultExtension: 'js'
    },
    (...)
  }
});

When specifying a outFile property, the TypeScript compiler generates a file that explicitly registers modules by name like this:

System.register('app.component', [ ...

They aren't anonymous modules as before. This way you don't need to configure SystemJS to associate JS files with module names (what you do with the packages block).

See this question for more details:

Upvotes: 0

Related Questions