web-dev-qa-db-fra.com

Webpack, TypeScript et Angular2 avec compilation AOT (Ahead Of Time)?

La dernière version d’Angular2 permet la compilation AOT, en utilisant ce code dans votre fichier app.bootstrap.ts:

// The browser platform without a compiler
import { platformBrowser } from '@angular/platform-browser';

// The app module factory produced by the static offline compiler
import { AppModuleNgFactory } from './app.module.ngfactory';

// Launch with the app module factory.
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);

Angular2 Documentation officielle

Comment pouvons-nous intégrer les chargeurs Webpack et TypeScript au compilateur AOT d'Angular2?

Il semble qu’il n’y ait pas encore d’option pour le faire, mais je pose la question sur le débordement de pile afin qu’il soit facile de trouver la réponse.

UPDATE 10/12/16 - Je l'ai fait fonctionner, voir ma réponse ci-dessous.

16
TetraDev

Je l’ai enfin fait, voir mon rapport/ Angular2 Webpack2 DotNET Starter

Il y a plusieurs astuces nécessaires. Notez que la compilation AOT ne prend en charge aucune instruction require() dans vos composants Angular 2. Ils devront être convertis en instructions import.

Tout d'abord, vous devez disposer d'un deuxième fichier tsconfig.json, avec des options spéciales pour la compilation AOT. Je désigne ceci avec l'extension .aot.json.

tsconfig.aot.json:

{
   "compilerOptions": {
      "target": "es5",
      "emitDecoratorMetadata": true,
      "experimentalDecorators": true,
      "allowSyntheticDefaultImports": false,
      "noEmitHelpers": true,
      "pretty": true,
      "strictNullChecks": false,
      "baseUrl": ".",
      "sourceMap": true,
      "sourceRoot": ".",
      "lib": [
         "es6",
         "dom"
      ],
      "types": [
         "lodash",
         "hammerjs",
         "jasmine",
         "node",
         "Selenium-webdriver",
         "source-map",
         "uglify-js",
         "webpack",
         "materialize-css",
         "jquery",
         "kendo-ui"
      ],
      "typeRoots": [
         "./node_modules/@types"
      ],
      "outDir": "./compiled/src"
   },
   "exclude": [
      "./node_modules",
      "./**/*.e2e.ts",
      "./**/*.spec.ts",
   ],
   "awesomeTypescriptLoaderOptions": {
      "useWebpackText": true,
      "forkChecker": true,
      "useCache": true
   },
   "compileOnSave": false,
   "buildOnSave": false,
   "atom": {
      "rewriteTsconfig": false
   },
   "angularCompilerOptions": {
      "genDir": "./compiled/aot",
      "debug": true
   }
}

Vous aurez également besoin de la bonne combinaison de versions de Angular2. @angular/[email protected] et @angular/[email protected] ne fonctionnaient PAS pour moi, je devais utiliser 2.0.0 pour les deux ou ngc n'a pas réussi à compiler les fichiers AOT. Voici ce que j'utilise avec succès:

package.json:

  "dependencies": {
    "@angular/core": "2.0.0",
    "@angular/common": "2.0.0",
    "@angular/compiler": "2.0.0",
    "@angular/compiler-cli": "0.6.2",
    "@angular/forms": "^2.0.1",
    "@angular/http": "2.0.0",
    "@angular/platform-browser": "2.0.0",
    "@angular/platform-browser-dynamic": "2.0.0",
    "@angular/platform-server": "2.0.0",
    "@angular/router": "3.0.0",
    "@angular/tsc-wrapped": "0.3.0"
}

En outre, vous aurez besoin de quelques chargeurs Webpack astucieux, tout en permettant à Webpack de rechercher dans le dossier ./src ainsi que le dossier dans lequel les fichiers compilés AOT sont générés. (*.component.ngfactory.ts

Cette dernière partie est très importante! Si vous ne dites pas à Webpack de l'inclure dans ces dossiers, cela ne fonctionnera pas. Dans cet exemple, les fichiers AOT sont générés dans /aot-compiled dans le dossier racine.

webpack.common.js

  loaders: [
     {
        test: /\.ts$/,
        include: [helpers.paths.appRoot, helpers.root('./compiled/aot')],
        exclude: [/\.(spec|e2e)\.ts$/],
        loaders: [
           '@angularclass/hmr-loader',
           'awesome-TypeScript-loader',
           'angular2-template-loader',
           'angular2-router-loader?loader=system',
           "angular2-load-children-loader" // this loader replaces loadChildren value to work with AOT/JIT
        ],
     },
  ]

Pour générer vos fichiers AOT, vous aurez besoin d'un script NPM pour le faire à votre place.

package.json

   "scripts": {
      "compile:aot": "./node_modules/.bin/ngc -p ./tsconfig.aot.json",
   }

Vous devrez également faire en sorte que votre configuration webpack lise la version AOT de app.bootstrap.ts - qui est différente de la version JIT. Je le différencie avec l'extension .aot.ts pour qu'en production, Webpack utilise AOT (app.bootstrap.aot.ts), mais en mode dev, il utilise JIT avec webpack-dev-server (app.bootstrap.ts).

Enfin, vous exécutez npm run compile:aot FIRST . Une fois que vos fichiers AOT sont sortis sur le disque, vous exécutez votre version de Webpack avec webpack ou webpack-dev-server.

Pour un exemple de travail, voir mon référentiel Angular2 Webpack2 DotNET Starter . Il est intégré à .NET Core 1.0, mais pour ceux qui n'utilisent pas .NET, vous pouvez toujours voir comment Webpack 2 et Angular 2 sont configurés.

8
TetraDev

tsconfig.json 

    {
      "compilerOptions": {
        "target": "es5",
        "module": "es2015",
        "moduleResolution": "node",
        "sourceMap": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "lib": ["es2015", "dom"],
        "noImplicitAny": true,
        "suppressImplicitAnyIndexErrors": true,
        "typeRoots": [
          "./node_modules/@types/"
        ]
      },
      "angularCompilerOptions": {
        "genDir": "aot",
        "skipMetadataEmit" : true
      }
    }

config/webpack-aot.config.js

/**
 * webpack2 config file for ng2 AOT compile
 * location : config/webpack.aot.js
 */
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var helpers = require('./helpers');

const ngToolsWebpack = require('@ngtools/webpack');
const ENV = process.env.NODE_ENV = process.env.ENV = 'production';
console.log(helpers.root('src', 'app', 'app.module#AppModule'));
module.exports = {
  devtool: 'source-map',
  entry: {
    'polyfills': './src/polyfills.ts',
    'app': './src/main.ts'
  },
  resolve: {
    extensions: ['*', '.ts', '.js']
  },
  output: {
    path: helpers.root('dist'),
    publicPath: '/',
    filename: '[name].[hash].js',
    chunkFilename: '[id].[hash].chunk.js'
  },

  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: '@ngtools/webpack'
      },
      {
        test: /\.html$/,
        loader: 'html-loader'
      },
      {
        test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
        include: helpers.root('public', 'images'),
        loader: 'file-loader',
        options: {
          //name: '/assets/[name].[hash].[ext]'  <-file-loaderError
          name: 'assets/[name].[ext]'
        }
      },
      {
        test: /\.css$/,
        exclude: helpers.root('src', 'app'),
        loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' })
      },
      {
        test: /\.css$/,
        include: helpers.root('src', 'app'),
        loader: 'raw-loader'
      },
      {
        test: /\.scss$/,
        exclude: /node_modules/,
        loaders: ['raw-loader', 'sass-loader']
      },
      {
        test: /\.sass$/,
        exclude: /node_modules/,
        loaders: ['raw-loader', 'sass-loader']
      }
    ]
  },

  plugins: [
    // If you want to use jquery in ng2 uncomment this
    /*
    new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery"
    }),*/
    new ngToolsWebpack.AotPlugin({
      tsConfigPath: helpers.root('tsconfig-aot.json'),
      basePath: helpers.root(''),
      entryModule: helpers.root('src', 'app', 'app.module#AppModule'),
      mainPath: helpers.root('src', 'main.ts')
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: ['app', 'polyfills']
    }),
    new webpack.LoaderOptionsPlugin({
      minimize: true,
      options: {
        htmlLoader: {
          minimize: false
        }
      }
    }),
    new HtmlWebpackPlugin({
      template: 'public/index.html'
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
          warnings: false,
          drop_console: true
      },
      output: {
          comments: false
      }
    }),
    new ExtractTextPlugin('[name].[hash].css'),
    new webpack.DefinePlugin({
      'process.env': {
        'ENV': JSON.stringify(ENV)
      }
    })
  ]
};

J'ai utilisé cette configuration webpack et j'ai compilé AOT avec angular2 lazy loading . Vous pouvez voir un exemple d'application pour compiler AOT/JIT avec angular2 lazy load pour le mode production et le mode dev dans ce git.

angular2-webpack2-aot

1
MiraGe