2016-07-01 39 views
6

Tôi hiện đang đóng gói ứng dụng Angular 2 của mình với WebPack. Chúng tôi vẫn đang quay vòng nhanh chóng, vì vậy thay vì thêm sự chậm trễ quá trình tải xây dựng và ứng dụng của chúng tôi, chúng tôi muốn bao gồm hiếm khi thay đổi góc 2 UMD CDN được điều chế bó, ví dụ:Gói ứng dụng Góc 2 sử dụng gói UMD (không xây dựng gói nhà cung cấp)

<script src="https://npmcdn.com/@angular/[email protected]/bundles/core.umd.min.js"></script> 
<script src="https://npmcdn.com/@angular/[email protected]/bundles/common.umd.min.js"></script> 
<script src="https://npmcdn.com/@angular/[email protected]/bundles/compiler.umd.min.js"></script> 
  • Khi tôi chỉ cho WebPack làm điều của nó, các gói chạy tốt nhưng là một vài MB, bởi vì nó không tận dụng các gói được xây dựng sẵn hoặc tách ra Angular 2 "nhà cung cấp" mã.
  • Khi tôi sử dụng Angular 2 WebPack Recommendations, ví dụ: plugins: [ new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.bundle.js") ], gói ứng dụng của tôi nhỏ, nhưng tôi xây dựng một gói 1MB độc đáo riêng biệt chứa hầu hết khung công tác Angular 2 trong đó, mọi bản dựng. Tệp này thay đổi một chút mỗi bản dựng tùy thuộc vào ứng dụng của tôi và không di chuyển giữa các phiên bản ứng dụng của tôi hoặc các ứng dụng khác nhau và không có lợi ích của "CDN". Tất nhiên tôi phải bao gồm tệp này để ứng dụng của tôi chạy.
  • Khi tôi sử dụng IgnorePlugin để lọc @angular|rxjs, ví dụ: plugins: [ new webpack.IgnorePlugin(/\@angular|rxjs/) ], nó loại trừ các tệp của nhà cung cấp, nhưng chèn các ngoại lệ mã hóa cứng/ném lỗi ở đầu gói ứng dụng của tôi.
  • Khi tôi sử dụng WebPack externals, ví dụ: externals: ['@angular/core', ..., tôi nhận được sản lượng function(module, exports) { module.exports = @angular/core; }, trong gói ứng dụng của mình, rõ ràng là không hoạt động. Các tài liệu WebPack không phải là terribly sắp tới, nhưng tôi nghĩ rằng tôi có thể có thể chỉ định một chức năng giải quyết libraryTarget hoặc trích dẫn, mà sẽ hướng dẫn WebPack để biên dịch trong tải mô-đun.
  • Khi tôi bỏ WebPack hoàn toàn và sử dụng trình biên dịch trình biên dịch TypeScript (theo this guide, sử dụng gói UMD), tôi nhận được các cuộc gọi System.register() đề cập đến không gian tên NPM mà tôi mong đợi, ví dụ: System.register("myapp/boot", ['@angular/core', ..., nhưng tôi vẫn đang làm việc trên cấu hình SystemJS để gọi UMD. Lưu ý phụ, tệp này có kích thước thêm 25% so với kích thước của WebPack.
  • Nếu tôi sử dụng SystemJS như trong mục trước, tôi muốn biên dịch này xảy ra trong khi xây dựng, hoặc như một quá trình song song, thay vì là một phần của lưu tệp. Tôi đoán SystemJS-Builder (xem câu hỏi liên quan herehere) sẽ là cách để làm điều này? Có lẽ điều này cũng sẽ tạo ra các kích thước tệp nhỏ hơn mà gói "tích hợp" của Typecript.

Làm cách nào để tạo gói ứng dụng không phụ thuộc vào gói Angular 2 được đóng gói lại độc đáo?

Tôi hiện đang xây dựng dựa trên RC3. Quá trình của tôi hiện là WebPack, như đã đề cập ở trên, nhưng tôi sẽ chuyển sang một bộ công cụ khác nếu điều đó giúp dễ dàng hơn.

Làm một số nghiên cứu khác, tôi nghĩ rằng tôi đã bị lừa bởi thuật ngữ "Loader" của WebPack. Tôi phải sử dụng một bộ nạp mô-đun, và nó không giống như WebPack có một mà sẽ làm việc cho việc này.

Để gán UMD gói không gian tên mô-đun (và dây phụ thuộc), chúng không thể được tải trong thẻ tập lệnh. Thay vào đó, chúng phải được đánh giá với bối cảnh this nhất định để hoạt động như tham chiếu mô-đun. Điều đó có nghĩa rằng ngay cả khi tôi muốn tất cả chúng được tải đồng bộ, tôi vẫn phải cấu hình một cái gì đó khác như SystemJS để tải chúng qua dây, vì vậy ngữ cảnh của chúng được điều khiển/bọc.

Điều này Angular 2 plunker là gần những gì tôi đang tìm kiếm. Nó sử dụng các gói Angular 2 UMD, nhưng không sử dụng một gói RxJs, mặc dù có vẻ dễ dàng, đủ để thay đổi nếu tôi muốn toàn bộ thư viện RxJs.

Trả lời

2

Nhiều cách tiếp cận trong câu hỏi của tôi sẽ hoạt động. Một số sẽ không, một số thì không hiện do khiếm khuyết trong góc 2. Dưới đây là cách tiếp cận Tôi hiện đang sử dụng:


WebPack + require.js

angular2-webpack-config.js

var config = { 
    entry: { 
     app: inputFile 
    }, 
    externals: [ 
     /^@angular\//, 
     /^rxjs\// 
    ], 
    output: { 
     libraryTarget: "amd", 
     path: __dirname, 
     filename: './' + outputName 
    }, 
    plugins: [ 
     new require('webpack').optimize.UglifyJsPlugin() 
    ] 
}; 

tôi chỉ nói với nó là gì và những gì externals giả tiêu chuẩn cơ chế sẽ tải chúng trong thời gian chạy qua libraryTarget (AMD/RequireJS, Comm onJs/node, UMD). Cài đặt của tôi chỉ đơn giản là làm cho các tham chiếu thư viện bên ngoài được gói trong define().

Lưu ý rằng tôi không làm gì với đường dẫn trong WebPack. Trong phần mềm của tôi, bất cứ thứ gì trong thư mục node_modules đều có cơ chế tham chiếu tương tự cả trong phần mềm của tôi và trong các mô-đun của bên thứ ba, trong nội bộ. Cả mã của tôi và thư viện của bên thứ ba đều mong muốn tìm RxJS tại rxjs (ví dụ: thay vì ../rxjs hoặc 'node_modules/rxjs`). Khi chạy, cả hai cần phải được ánh xạ, nhưng vì chúng tôi không cho phép WebPack tiếp cận với các mô-đun bên thứ ba (chúng tôi đang sử dụng UMD được dựng sẵn), WebPack không phải là nơi để thực hiện ánh xạ đó. Nó sẽ chỉ lập bản đồ mã của tôi. Thay vào đó, chúng tôi nên làm điều đó trong trình tải thời gian chạy của chúng tôi:

chỉ mục.htm

<script src="https://npmcdn.com/core-js/client/shim.min.js"></script> 
<script src="https://npmcdn.com/[email protected]/dist/zone.min.js"></script> 
<script src="https://cdnjs.cloudflare.com/ajax/libs/reflect-metadata/0.1.3/Reflect.min.js"></script> 
<script> 
    var require = (function(){ 
     var versions = { 
      'router-deprecated': '@@2.0.0-rc.2', 
      'forms': '@@0.1.1', 
      'angular': '@@2.0.0-rc.4', 
      'rxjs': '@@5.0.0-beta.10' 
     } 

     var paths = { 
      'rxjs': "https://npmcdn.com/rxjs" + versions.rxjs + "/bundles/Rx.umd.min" 
     }; 
     [ 
      'core', 
      'http', 
      'common', 
      'compiler', 
      'platform-browser', 
      'router-deprecated', 
      'platform-browser-dynamic' 
     ].forEach(function (submodule) { 
      var module = '@@angular/' + submodule 
      paths[module] = 'https://npmcdn.com/' + module + (versions[submodule] || versions.angular) + '/bundles/' + submodule + '.umd.min'; 
     }); 

     var rxmap = {}; 
     [ 
      'Rx', 
      'Observable', 
      'Subject', 
      'observable/PromiseObservable', 
      'operator/toPromise' 
     ].forEach(function (submodule) { 
      rxmap['rxjs/' + submodule] = 'rxjs'; 
     }) 

     return { 
      paths: paths, 
      map: { 
       '*': rxmap 
      } 
     }; 
    })(); 
</script> 
<script data-main="../assets/compiled/a2.webpack.js" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.2.0/require.min.js"></script> 

Ngoài ra, vì nếu bạn đang sử dụng WebPack và UMDs bạn có thể quan tâm đến kết quả là kích thước file và thời gian. Quá trình xây dựng Angular 2 của ứng dụng phụ này đã tăng từ khoảng 24 giây lên 1 giây. Xuất bản của nó thay đổi kích thước đã đi từ hơn 2MB đến khoảng 100k.

Đây là kích thước tải dây của các phụ thuộc được lưu trong bộ nhớ cache để tham khảo. Thật lạ là hiện tại chúng chỉ có một vài KB nhỏ hơn trong phiên bản UMD so với việc tăng kích thước dây của gói tích hợp, WebPack bị cắt xén.

KB 
27.5 shim 
6.8 zone 
8.0 require 
3.3 platform-browser-dynamic 
36.8 http 
8.7 core 
20.8 common 
16.5 router 
98.5 compiler 
27.9 platform-browser 
39.0 Rx 

Rõ ràng thời gian tải trang web công cộng của tôi sau khi cập nhật giảm đáng kể (xuống còn 1 giây từ khoảng 10-20 giây), nhưng những con số này khá thay đổi dựa trên kết nối.

1

Tôi đã cố gắng đạt được kết quả tương tự mà không thành công cho đến thời điểm này.

Như một nỗ lực đầu tiên, tôi quản lý để có webpack tải UMD pre-built bó sử dụng resolve cấu hình, như trong ví dụ dưới đây:

var webpack = require('webpack'); 

module.exports = { 
    entry: './src/main', 
    output: { 
    filename: 'bundle.js', 
    path: 'bundles/app', 
    }, 

    resolve: { 
    extensions: ['', '.ts', '.js'], 
    alias: { 
     '@angular/common' : '@angular/common/common.umd.js', 
     '@angular/compiler' : '@angular/compiler/compiler.umd.js', 
     '@angular/core' : '@angular/core/core.umd.js', 
     '@angular/http' : '@angular/http/http.umd.js', 
     '@angular/platform-browser' : '@angular/platform-browser/platform-browser.umd.js', 
     '@angular/platform-browser-dynamic' : '@angular/platform-browser-dynamic/platform-browser-dynamic.umd.js', 
     '@angular/router' : '@angular/router/router.umd.js', 
     '@angular/router-deprecated' : '@angular/router-deprecated/router-deprecated.umd.js', 
     '@angular/upgrade' : '@angular/upgrade/upgrade.umd.js', 
     'rxjs/Observable' : 'rxjs/bundles/Rx.umd.min.js', 
     'rxjs/add/operator/map' : 'rxjs/bundles/Rx.umd.min.js', 
     'rxjs/add/observable/fromEvent' : 'rxjs/bundles/Rx.umd.min.js', 
     rxjs : 'rxjs/bundles/Rx.umd.min.js' 
    } 
    }, 

    module: { 
    loaders: [ 
     {test: /\.ts$/, exclude: /node_modules/, loader: 'ts'}, 
    ], 
    noParse: [/@angular/, /rxjs/] 
    }, 

}; 

Các cấu hình mấu chốt ở đây là noParseresolve/alias. Tôi đang yêu cầu webpack tải các gói được tạo sẵn UMD bất cứ khi nào tìm thấy các yêu cầu như @angular/common và v.v.

Cấu hình này làm cho tệp web bao gồm tệp UMD thay vì xử lý từng tệp góc và rxj. Mục tiêu của tôi ở đây là cải thiện thời gian xây dựng. Tuy nhiên, trong trường hợp của tôi, ứng dụng của tôi không thành công khi chạy. Tôi đoán tôi đã sử dụng một thư viện đòi hỏi các tập tin góc trên src thư mục của nó và nó đã làm cho nó thất bại. Tôi muốn cung cấp cho thiết lập này một thử để kiểm tra xem nó hoạt động trên kịch bản của bạn.

Là nỗ lực thứ hai, tôi đã thử một tính năng có tên là Webpack DLL như được mô tả tại http://engineering.invisionapp.com/post/optimizing-webpack/. Nó tạo ra một bó có thể được tái sử dụng trên các bản xây dựng, do đó tránh tái đóng gói angular2 mọi lúc. Unfortunatelly ứng dụng của tôi không có ngoại lệ tiêm phụ thuộc với kịch bản này.

tôi đã quản lý để load UMD bó sử dụng SystemJS thay vì Webpack, với các thiết lập sau

(function(global) { 

    var paths = { 
    'jquery' : '../node_modules/jquery/dist/jquery.js', 
    'bootstrap' : '../node_modules/bootstrap/dist/js/bootstrap.js', 
    //'rxjs/*' : '../node_modules/rxjs/bundles/Rx.umd.min.js', //FAILS with router 3.0 
    } 

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

    var packages = { 
    'app':      { main: 'main.js', defaultExtension: 'js' }, 
    'angular2-in-memory-web-api': { defaultExtension: 'js' }, 
    'lodash':      { main: 'lodash.js', defaultExtension: 'js' }, 
    'rxjs':      { defaultExtension: 'js' }, 
    }; 

    var ngPackageNames = [ 
    'common', 
    'compiler', 
    'core', 
    'http', 
    'platform-browser', 
    'platform-browser-dynamic', 
    'router', 
    'router-deprecated', 
    'upgrade', 
    ]; 
    ngPackageNames.forEach(function(pkgName) { 
    packages['@angular/'+pkgName] = { main: '/bundles/' + pkgName + '.umd.js', defaultExtension: 'js' }; 
    }); 

    var config = { 
    map: map, 
    packages: packages, 
    paths : paths, 
    }; 

    // filterSystemConfig - index.html's chance to modify config before we register it. 
    if (global.filterSystemConfig) { global.filterSystemConfig(config); } 

    System.config(config); 

})(this); 

này là khá mych thiết lập bởi các tài liệu chính thức Angular2 với việc bổ sung path phần đề xuất. Nó được sử dụng để có thể tải RxJS như một gói UMD duy nhất nhưng với việc giới thiệu gần đây của router 3.0 thiết lập này không thành công với các ngoại lệ trên mã bộ định tuyến. Tôi phải hoàn nguyên và tải lại RxJS làm yêu cầu riêng lẻ.

+0

Vâng, hiện giờ tôi cũng đang hoạt động với các gói SystemJS, mặc dù tôi vẫn đang sử dụng 'không dùng nữa bộ định tuyến', vì vậy không có nhận xét nào về vấn đề đó, bằng cách sử dụng SystemJS-Builder. Đó có phải là cách bạn đang làm điều này? Bằng cách nào đó bạn vẫn cần phải tiêu thụ các gói UMD, mã SystemJS bạn chỉ hiển thị cấu hình chúng. Bạn cũng có thể ánh xạ chúng thành các hình cầu, và ánh xạ theo cách thủ công thành các hình cầu trong cấu hình webpack "Externals", tương tự như những gì tôi đang cố gắng (sử dụng require.js chỉ vì nó nhỏ hơn). – shannon

+0

Bạn muốn trò chuyện về điều này? – shannon

+0

Lưu ý rằng tôi đã thường xuyên cập nhật những khám phá của mình trong câu hỏi của tôi ở trên. Tất nhiên tôi sẽ cung cấp một câu trả lời nếu tôi tìm thấy một giải pháp phù hợp trước khi một được đăng. – shannon

Các vấn đề liên quan