简体   繁体   中英

How to combine (minify) compiled Angular 2 components?

trying to minify compiled source code of a project for production, I'm using Gulp as the task runner.

the source files look like this,

html

<!--... . .  various scripts and styles . . . . . --->
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<script src="node_modules/angular2/bundles/router.dev.js"></script>
<script src="node_modules/angular2/bundles/http.dev.js"></script>

<script>
  System.config({
    packages: {        
      app: {
        format: 'register',
        defaultExtension: 'js'
      }
    }
  });
  System.import('app/main')
        .then(null, console.error.bind(console));
</script>
</head>
<body>
  <app></app>
</body>

my app directory structure is as follows,

.
├── main.js
├── main.js.map
├── main.ts
├── main.app.js
├── main.app.js.map
├── main.app.ts
├── x.component1
│   ├── x.component.one.js
│   ├── x.component.one.js.map
│   └── x.component.one.ts
└── x.component2
    ├── x.component.two.js
    ├── x.component.two.js.map
    └── x.component.two.ts

app/main.ts

import {bootstrap}    from 'angular2/platform/browser';
import {MyAwesomeApp} from './main.app'

bootstrap(MyAwesomeApp);

main.app.ts

@Component({
    selector: 'app',
    template: `
        <component-1></component-1>

        <component-2></component-2>
    `,
    directives: [Component1, Component2]
})


export class MyAwesomeApp {

}

then the components,

@Component({
    selector: 'component-1',
    template: `
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Beatae ducimus, saepe fugit illum fuga praesentium rem, similique deserunt tenetur laudantium et labore cupiditate veniam qui impedit, earum commodi quasi sequi.
    `
})


export class Component1 {

}

and

@Component({
    selector: 'component-2',
    template: `
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Beatae ducimus, saepe fugit illum fuga praesentium rem, similique deserunt tenetur laudantium et labore cupiditate veniam qui impedit, earum commodi quasi sequi.
    `
})


export class Component2 {

}

All the TypeScript files are compiled down to ES5 JavaScript, further need to minified to main.js

so my questions are,

  1. Can I run a task to collect all the compiled .js files to minify to a single file and reference it as main in production branch?
  2. Does this breaks the module system import {x} from 'y'?
  3. If it breaks the module loading system, what can be done to concatenate files on an Angular 2 application?

my TypeScript version is, 1.8.2

Thank you for any help.

If you want to compile all your TypeScript files into a single one, you need to use the outFile property of the TypeScript compiler. It's configurable through the gulp-typescript plugin.

This way you don't need to configure SystemJS to load module based on file names:

<script>
  // Not necessary anymore
  /* System.config({
    packages: {        
      app: {
        format: 'register',
        defaultExtension: 'js'
      }
    }
  }); */
  System.import('app/main')
        .then(null, console.error.bind(console));
</script>

The module names and their contents are now present in this single file. The same way for the packaged bundle files of the Angular2 distribution ( angular2.dev.js , http.dev.js , ...). To use this file, simply include it in a script element.

This way you won't break module imports.

Then you can minify this single file with the uglify plugin of gulp...

** Create a single file from TS with options in tsconfig.json.

{
  "compilerOptions": {
    "target": "es5",
    "module": "system",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": true,
    "noImplicitAny": false,
    "outDir":"client/build/",
    "outFile": "client/build/all.js",
    "declaration": true
  },
  "exclude": [
    "node_modules",
    "server"
  ],
  "include": [
        "client/*.ts",
        "client/**/*.ts",
        "client/**/**/*.ts"
  ]   
}

// Include all folders to put to a file.

** Build the output file and include as follows: Example:

<script>


  // Alternative way is compile in all.js and use the following system config with all the modules added to the bundles.
  // the bundle at build/all.js contains these modules
System.config({
    bundles: {
      'client/build/all.js': ['boot','components/all/present','components/main/main','components/register/register','components/login/login','components/home/home','services/userdetails','services/httpprovider']
    }
  });

  // when we load 'app/app' the bundle extension interrupts the loading process
  // and ensures that boot of build/all.js is loaded first
  System.import('boot');


    </script>

** Minify the all.js file as you do normally.

Since you are already using Gulp you can just add webpack in your gulp task to combine all your JavaScript source files (as well as Angular2 sources) into one. Here's a sample of what your webpack.config.js could look like:

module.exports = {
  entry: './src/app/app',
  output: {
    path: __dirname + '/src', publicPath: 'src/', filename: 'bundle.js'
  },
  resolve: {
    extensions: ['', '.js', '.ts']
  },
  module: {
    loaders: [{
      test: /\.ts/, loaders: ['ts-loader'], exclude: /node_modules/
    }]
  }
};

The relevant sections from your gulpfile.js are

var webpack = require('webpack-stream');
var htmlReplace = require('gulp-html-replace');
var gulp = require('gulp');

gulp.task('webpack', function() {
  return gulp.src('src/app/*.ts')
    .pipe(webpack(require('./webpack.config.js')))
    .pipe(gulp.dest('src/'));
});

Replace gulp.dest('src/') with the relevant location that you want your production code to reside in.

You then need to process your HTML files to have the appropriate JavaScript source file references (also in gulpfile.js ).

gulp.task('html', ['templates'], function() {
  return gulp.src('src/index.html')
    .pipe(htmlReplace({
      'js': ['bundle.js']
    }))
    .pipe(gulp.dest('dist/'));
});

If you want to minify your JavaScript files you can use UglifyJS2 . (Note however that there is something that goes wrong with obfuscation, hence the mangle: false . See this SO link for more). Here's the relevant gulpfile.js content:

gulp.task('js', ['webpack'], function() {
  return gulp.src('src/bundle.js')
    .pipe(uglify({
            mangle: false
          }))
    .pipe(gulp.dest('dist/'));
});

In this way your production code ends up in your dist folder from where you can deploy it. Now it's your choice whether you check that into a production branch or not.

Feel free to refer to my words project on Github if you want to see a working version on a very small Angular2 app.

If you are using @angular/cli you can run

ng build --prod

to minify and gzip the code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM