Otimize a duração da construção do aplicativo Angular 2 com o webpack

9

Eu construo um aplicativo Angular 2 e o empacoto com o webpack. No momento, meu aplicativo ainda é pequeno, mas a tarefa do webpack já leva cerca de 10 segundos. É possível otimizar minha configuração do webpack ou as opções de compilação do TypeSript para melhorar a duração da compilação e da embalagem?

Esta é a configuração do webpack que eu uso:

var webpack = require('webpack');
var LiveReloadPlugin = require('webpack-livereload-plugin');

module.exports = {
  entry: __dirname + '/assets/app/app.ts',
  output: {
    filename: 'myApp.bundle.js',
    path: __dirname + '/build/'
  },
  // Turn on sourcemaps
  devtool: 'source-map',
  resolve: {
    extensions: ['.ts', '.js']
  },
  plugins: [
    new LiveReloadPlugin({
      appendScriptTag: true
    }),
    // Fixes angular 2 warning
    new webpack.ContextReplacementPlugin(
      /angular(\|\/)core(\|\/)(esm(\|\/)src|src)(\|\/)linker/,
      __dirname
    )
  ],
  module: {
    rules: [{
        enforce: 'pre',
        test: /\.js$/,
        loader: "source-map-loader"
      },
      {
        enforce: 'pre',
        test: /\.tsx?$/,
        use: "ts-loader"
      }
    ]
  }
}

E o tsconfig:

{
  "compilerOptions": {
    "target": "ES5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "pretty": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "noUnusedLocals": false,
    "removeComments": true,
    "skipLibCheck": true,
    "strictNullChecks": false,
    "baseUrl": "./src",
    "typeRoots": ["node_modules/@types"],
    "types": [
      "core-js",
      "systemjs"
    ],
    "outDir": "./build"
  },
  "exclude": [
    "node_modules"
  ]
}

UPDATE (veja minha resposta para o webpack.config fixo)

Eu experimento o plugin de webpack de DLL sugerido por @jpwiddy, compilando o angular em uma construção separada, para ter que reconstruir somente o código do aplicativo durante os desenvolvimentos e ganhar um tempo considerável de compilação.

No entanto, após uma inspeção da saída JS, o tamanho do arquivo é o mesmo e ainda há código angular interno.

Aqui está o novo arquivo de configuração do webpack para fontes angulares:

var webpack = require('webpack');

module.exports = {
  entry: {
      angular:[
        '@angular/platform-browser',
        '@angular/platform-browser-dynamic',
        '@angular/core',
        '@angular/common',
        '@angular/compiler',
        '@angular/http',
        '@angular/router',
        '@angular/forms'        
    ]
  },
  output: {
    filename: 'ng2.dll.js',
    path: __dirname + '/build/',
    library: 'ng2'
  },
  plugins: [
    // Fixes angular 2 warning
    new webpack.ContextReplacementPlugin(
      /angular(\|\/)core(\|\/)(esm(\|\/)src|src)(\|\/)linker/,
      __dirname
    ),
    new webpack.DllPlugin({ 
        name: 'ng2', 
        path: __dirname + '/build/ng2.json'
    })
  ]
}

E a configuração atualizada do webpack para o aplicativo:

var webpack = require('webpack');
var LiveReloadPlugin = require('webpack-livereload-plugin');

module.exports = {
  entry: __dirname + '/assets/app/app.ts',
  output: {
    filename: 'myApp.bundle.js',
    path: __dirname + '/build/'
  },
  // Turn on sourcemaps
  devtool: 'source-map',
  resolve: {
    extensions: ['.ts', '.js']
  },
  plugins: [
    new LiveReloadPlugin({
      appendScriptTag: true
    }),
    // Fixes angular 2 warning
    new webpack.ContextReplacementPlugin(
      /angular(\|\/)core(\|\/)(esm(\|\/)src|src)(\|\/)linker/,
      __dirname
    ),
    new webpack.DllReferencePlugin({
      context: __dirname + '/build/',
      manifest: require(__dirname + '/build/ng2.json')
    })
  ],
  module: {
    rules: [{
        enforce: 'pre',
        test: /\.js$/,
        loader: "source-map-loader"
      },
      {
        enforce: 'pre',
        test: /\.tsx?$/,
        use: "ts-loader"
      }
    ]
  }
}

Aqui está um dos códigos angulares que encontrei na saída JS do meu aplicativo:

_TsEmitterVisitor.prototype.visitBuiltintType = function (type, ctx) {
    var typeStr;
    switch (type.name) {
        case __WEBPACK_IMPORTED_MODULE_2__output_ast__["R" /* BuiltinTypeName */].Bool:
            typeStr = 'boolean';
            break;
        case __WEBPACK_IMPORTED_MODULE_2__output_ast__["R" /* BuiltinTypeName */].Dynamic:
            typeStr = 'any';
            break;
        case __WEBPACK_IMPORTED_MODULE_2__output_ast__["R" /* BuiltinTypeName */].Function:
            typeStr = 'Function';
            break;
        case __WEBPACK_IMPORTED_MODULE_2__output_ast__["R" /* BuiltinTypeName */].Number:
            typeStr = 'number';
            break;
        case __WEBPACK_IMPORTED_MODULE_2__output_ast__["R" /* BuiltinTypeName */].Int:
            typeStr = 'number';
            break;
        case __WEBPACK_IMPORTED_MODULE_2__output_ast__["R" /* BuiltinTypeName */].String:
            typeStr = 'string';
            break;
        default:
            throw new Error("Unsupported builtin type " + type.name);
    }
    ctx.print(typeStr);
    return null;
 };

Eu perdi alguma coisa na nova configuração para impedir que o webpack inclua fontes angulares na saída?

Obrigado

    
por bviale 23.02.2017 в 17:28
fonte

2 respostas

0

Consegui consertar minha configuração com o novo módulo webpack-dll-bundles-plugin ( que usa DllPlugin e DllReferencePlugin em segundo plano) fazendo exatamente o que eu estava procurando: isolar a compilação de Angular 2 em seu próprio pacote e evitar a recompilação de todo o pacote toda vez que eu quero recriar o código do meu aplicativo (por exemplo, com um observador).

Meu tempo de reconstrução caiu de 10 segundos para 1 segundo.

Aqui está minha nova configuração do webpack:

var webpack = require('webpack');
var LiveReloadPlugin = require('webpack-livereload-plugin');
const DllBundlesPlugin = require('webpack-dll-bundles-plugin').DllBundlesPlugin;

module.exports = {
  entry: __dirname + '/assets/app/app.ts',
  output: {
    filename: 'myApp.bundle.js',
    path: __dirname + '/build/'
  },
  // Turn on sourcemaps
  devtool: 'source-map',
  resolve: {
    extensions: ['.ts', '.js']
  },
  plugins: [
    new LiveReloadPlugin({
      appendScriptTag: true
    }),
    // Fixes angular 2 warning
    new webpack.ContextReplacementPlugin(
      /angular(\|\/)core(\|\/)(esm(\|\/)src|src)(\|\/)linker/,
      __dirname
    ),
    new DllBundlesPlugin({
        bundles: {
          vendor: [
            '@angular/platform-browser',
            '@angular/platform-browser-dynamic',
            '@angular/core',
            '@angular/common',
            '@angular/forms',
            '@angular/http',
            '@angular/router',
            'rxjs',
          ]
        },
        dllDir:  __dirname + '/build/',
        webpackConfig: {}
      })
  ],
  module: {
    rules: [{
        enforce: 'pre',
        test: /\.js$/,
        loader: "source-map-loader"
      },
      {
        enforce: 'pre',
        test: /\.tsx?$/,
        use: "ts-loader"
      }
    ]
  }
}
    
por bviale 02.03.2017 / 18:09
fonte
2

Uma ótima maneira que eu pessoalmente fiz e acelerou o processo de criação do Webpack é a implementação de DLLs em sua compilação.

O Webpack trabalha analisando seu código para require s e import s e, em seguida, constrói uma tabela a partir dessas instruções de todas as dependências de seu módulo e vincula onde esses arquivos podem ser encontrados.

O plugin DLL melhora isso, como quando você registra suas dependências com uma DLL, toda vez que essas dependências mudam (deve ser muito pouco frequente), você constrói uma DLL (composta de um pacote javascript e um arquivo de manifesto JSON) e envolve todas essas dependências em um único pacote. Esse pacote é então referenciado ao inserir essas dependências no aplicativo.

Um exemplo rápido:

entry: {
    angular:[
        '@angular/platform-browser',
        '@angular/platform-browser-dynamic',
        '@angular/core',
        '@angular/common',
        '@angular/compiler',
        '@angular/http',
        '@angular/router',
        '@angular/forms'        
    ],
    bs: [
        'bootstrap', 
        'ng-bootstrap'
    ]
}, 

output: { 
    filename: '[name].dll.js', 
    path: outputPath, 
    library: '[name]', 
}, 

plugins: [ 
    new webpack.DllPlugin({ 
        name: '[name]', 
        path: join(outputPath, '[name].json') 
    })
]

... e depois referenciados como -

{
    plugins: [ 
        new webpack.DllReferencePlugin({
            context: process.cwd(),
            manifest: require(join(outputPath, 'angular.json'))
        }),
        new webpack.DllReferencePlugin({
            context: process.cwd(),
            manifest: require(join(outputPath, 'bs.json'))
        }),
    ]
}
    
por jpwiddy 23.02.2017 / 18:47
fonte