使用 webpack 优化 Angular 2 应用程序构建持续时间

Posted

技术标签:

【中文标题】使用 webpack 优化 Angular 2 应用程序构建持续时间【英文标题】:Optimize Angular 2 application build duration with webpack 【发布时间】:2017-07-14 06:11:36 【问题描述】:

我构建了一个 Angular 2 应用程序并将其与 webpack 捆绑在一起。 目前,我的应用程序仍然很小,但 webpack 任务已经花费了大约 10 秒。 是否可以优化我的 webpack 配置或 TypeSript 编译选项以提高编译和打包时间?

这是我使用的 webpack 配置:

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"
      
    ]
  

还有 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"
  ]

更新 (查看我对固定 webpack.config 的回答)

我尝试了@jpwiddy 建议的 DLL webpack 插件,方法是在单独的构建中编译 Angular,以便在开发过程中只需要重新构建应用程序代码并获得大量编译时间。

但是查看了输出的JS,文件大小还是一样的,里面还是有角码的。

这是 Angular 资源的新 webpack 配置文件:

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'
    )
  ]

以及更新的应用程序 webpack 配置:

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"
      
    ]
  

这是我在我的应用程序 JS 输出中找到的 Angular 代码之一:

_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;
 ;

我是否错过了新配置中的某些内容以防止 webpack 在输出中包含角度源?

谢谢

【问题讨论】:

commons-chunk-plugin 也可能有帮助。查看angular2-webpack-brief-starter 的配置,了解如何将其专门用于所有供应商文件(包括角度文件)。 【参考方案1】:

我设法用全新的模块 webpack-dll-bundles-plugin(在后台使用 DllPluginDllReferencePlugin)修复了我的配置,这正是我想要的:隔离在他自己的包中构建 Angular 2,并避免每次我想重建我的应用程序代码时都重建我的整个包(例如,使用观察者)。

我的重建时间从 10 秒减少到 1 秒。

这是我的新 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"
      
    ]
  

【讨论】:

【参考方案2】:

我个人加快 Webpack 构建过程的一个好方法是在您的构建中实现 DLL。

Webpack 的工作原理是分析 requires 和 imports 的代码,然后根据这些语句构建一个表,其中包含所有模块依赖项和指向这些文件所在位置的链接。

DLL 插件对此进行了改进,因为当您使用 DLL 注册依赖项时,每次这些依赖项发生变化 (应该非常罕见),您构建一个 DLL(由一个 javascript 包和一个 JSON 清单文件组成)和将所有这些依赖项包装在一个包中。然后在将这些依赖项拉入应用程序时引用该包。

一个简单的例子:

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') 
    )
]

...然后这样引用-


    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'))
        ),
    ]

【讨论】:

嗨@jpwiddy,谢谢你的回答。我尝试了您的 DLL 解决方案,但没有得到预期的结果。如果您觉得有些奇怪,您能否在我更新的帖子中检查我的配置文件?谢谢你:) @bviale 你能把我的答案标记为正确吗? :)

以上是关于使用 webpack 优化 Angular 2 应用程序构建持续时间的主要内容,如果未能解决你的问题,请参考以下文章

Angular、Nx Workspace、Webpack 5 Module Federation:您提供了一个无效的对象

92% 块资源优化 - webpack

Angular2-Webpack-Typescript - 3rd 方库

Angular/Webpack 未将 styleUrls 绑定到组件

Angular2 webpack:如何导入引导 css

Angular 2 的 JSPM 与 WebPack