2016-05-14 16 views
12

Tôi đang sử dụng Webpack và tôi muốn chia mã khách hàng thành nhiều phần và tải chúng khi người dùng cần chúng.Làm thế nào để tách mã trong Webpack với require.ensure cho sản xuất?

Dưới đây là cấu trúc tập tin của tôi:

app.js  <-- Entry point as introduced to Webpack 
Module.js <-- To be loaded dynamically 

Không có kết nối trực tiếp giữa app.jsModule.js, thay vào đó là tập thứ hai được nạp bởi người đầu tiên như thế này:

require.ensure([], (require) => { 
    let path = "Module"; 
    let module = require("./" + path).default; 
}); 

tôi đã sử dụng "./" + path chỉ để chắc chắc chắn Webpack sẽ không thông minh với tôi và cố gắng giải quyết đường dẫn tĩnh. Dù sao, mã này hoạt động trong chế độ phát triển với webpack-dev-server. Bởi vì tôi có nghĩa là Module.js không được tải xuống cho đến khi tôi kích hoạt sự kiện để chạy mã trên. Và sau đó, nó được nạp và thực hiện một cách hoàn hảo.

Nhưng khi tôi đóng gói dự án để sản xuất, nó sẽ ngừng hoạt động. Nó đưa ra các lỗi sau (trong trình duyệt khi tôi kích hoạt các sự kiện tải về) mà không cần cố gắng để gửi yêu cầu:

Uncaught Error: Cannot find module './Module'.

Hơn nữa, khi tôi soạn con đường tự động (như mã ở trên), quá trình xây dựng đưa ra cảnh báo sau:

WARNING in ./src/app/app.js Critical dependencies: 74:34-47 the request of a dependency is an expression

Cách nào đúng để định cấu hình Webpack cho sản xuất để hỗ trợ chia tách mã được tự động?


Tôi đã thử nghiệm giải pháp được đưa ra bởi @wollnyst và đây là kết quả. Khi tôi thực hiện nó như thế này, nó hoạt động:

require.ensure(["./Module"], (require) => { 
    let path = "Module"; 
    let module = require("./" + path).default; 
}); 

Nhưng đó không phải là cách tôi muốn nó, tôi muốn nó như thế này:

let path = "Module"; 
require.ensure(["./" + path], (require) => { 
    let module = require("./" + path).default; 
}); 

Bây giờ nó mang lại cho ra một lỗi thời gian chạy trong trình duyệt:

Uncaught TypeError: webpack_require(...).ensure is not a function

Vẫn không may mắn!

+0

Bạn không cần phải làm cho đường dẫn mô-đun động chỉ để làm cho nó tải động. 'require.ensure' quan tâm đến điều đó. Đường dẫn tĩnh sẽ hoạt động tốt trong trường hợp của bạn – raiyan

+1

@RaiyanMohammed Tôi xin lỗi nhưng tôi không làm theo! Trong đoạn code trên tôi đang tạo ra con đường năng động bởi vì trong cuộc sống thực, tôi có nó theo cách đó. Đường dẫn đến mô-đun không xác định tại thời điểm viết mã. Nó chỉ là thời gian chạy mà đường dẫn được chỉ định trong một biến. – Mehran

+1

Đây là vấn đề: Ngược lại với nút yêu cầu, webpack là tĩnh. Nó chạy một lần tại thời gian xây dựng. Do đó, webpack không thể đánh giá 'require' động. Bạn có chính xác cấu trúc nào? Có thể xác định [ngữ cảnh] của riêng mình (https://webpack.github.io/docs/context.html) có thể hữu ích. – wollnyst

Trả lời

1

Bạn cần phải vượt qua các module bạn muốn yêu cầu trong số đầu tiên của require.ensure:

require.ensure(['./Module'], function(require) { 
    const module = require('./Module'); 
}); 
+1

Giải pháp của bạn kinda hoạt động và kinda không! Tôi đã bao gồm các kết quả trong câu hỏi. Cảm ơn. – Mehran

3

Đưa đường dẫn mà bạn muốn yêu cầu tự động trong require.ensure mảng đối số đầu tiên là sai và không nên được thực hiện. Mảng này được thiết kế để sử dụng cho các phụ thuộc phụ thuộc của mô-đun bạn muốn tải động và cần thiết cho mã async trong gọi lại của bạn để chạy an toàn.

Phần quan trọng trong việc hiểu cách webpack có thể xử lý việc tách mã là bạn không thể thực hiện các câu lệnh động đầy đủ, vì webpack cần một số thông tin vị trí để giải quyết mô-đun bạn muốn yêu cầu, cảnh báo dependency is an expression. Ngay cả khi bạn có thể đi thông minh như bạn đã làm bằng cách preprending các ./, nó là thích hợp hơn để thực sự lặp lại các tuyên bố đầy đủ ensure với chuỗi đường dẫn mô-đun tĩnh ngay cả khi bạn có rất nhiều mô-đun để tự động tải và nó là một chút obnoxious, để bạn sẽ không gặp bất kỳ vấn đề nào.

Một cách khác để thực hiện việc này là tạo một thư mục dành riêng cho mục đích đó, ví dụ: splits và giải quyết tất cả các mô-đun của bạn từ đây. Nhưng điều đó có nghĩa là mọi mô-đun bạn yêu cầu trong thư mục này sẽ nằm trong cùng một điểm phân tách, không thực sự là điều mà bất kỳ ai muốn trừ các trường hợp sử dụng cụ thể.


Về configs, bạn sẽ cần phải sử dụng namedModulesPluginsCommonsChunkPlugin một. Những gì cá nhân tôi làm là có một số main.js có chứa tất cả các nguồn phổ biến, vendor.js, chứa tất cả các thông tin node_modulesruntime.js (yêu cầu của webpack). Sau đó, các khối được tách ra và nếu một phần phụ thuộc vào một sự phụ thuộc của nhà cung cấp cụ thể, nó sẽ được thêm vào đoạn cụ thể này chứ không phải là thông thường vendor.js.

plugins: [ 
    new webpack.NamedModulesPlugin(), 
    new webpack.optimize.CommonsChunkPlugin({ 
    name: 'vendor', 
    minChunks: module => module.context && module.context.indexOf('node_modules'), 
    }), 
    new webpack.optimize.CommonsChunkPlugin({ 
    name: 'runtime', 
    }), 
], 

Bạn cũng có thể chắc chắn rằng có một cái gì đó như sau output.filename:

output: { 
    filename: '[name]-[chunkhash].js', 
} 

Nếu các hash của vendor.js bạn sẽ thay đổi mọi nguồn của bạn thay đổi, ngay cả khi bạn không sửa đổi DEPS của bạn, đó là xấu nếu bạn lo lắng về bộ nhớ đệm.

webpack visualizer gần đây là một công cụ rất tốt để kiểm tra xem bó và khối của bạn trông như thế nào và để xác minh mọi thứ có vẻ ổn hoặc phát hiện các phụ thuộc có thể được chunked tốt hơn. Bạn có thể cần phải thay đổi một chút cấu hình của bạn nếu sử dụng StatsWriterPlugin để thu thập các số liệu thống kê để nó xử lý khối của bạn:

new StatsWriterPlugin({ 
    fields: null, 
    transform: (data, opts) => { 
    const stats = opts.compiler.getStats().toJson({ chunkModules: true }) 
    return JSON.stringify(stats, null, 2) 
    }, 
}), 

Một điều cần lưu ý quá, là require.ensure là cụ thể cho webpack và đang được thay thế bởi import() mà nó bây giờ cũng xử lý. Vì câu hỏi này là từ năm 2016 và nó có thể không có cùng một yếu tố chúng tôi có bây giờ với webpack 2, tôi sẽ mở rộng một chút về nó.

Hiện tại, đề xuất dynamic import đang được đưa vào ES và bạn có thể sử dụng nó trong webpack. Bạn sẽ yêu cầu một số Promise polyfill và một cái gì đó giống như plugin babel syntax-dynamic-import (và bây giờ sẽ ở trong stage-3 preset) hoặc dynamic-import-webpack nếu điều đó không hiệu quả với bạn (về cơ bản chuyển đổi import() thành ensures).

Bạn vẫn sẽ cần xác định đường dẫn đầy đủ như với đảm bảo nếu bạn muốn lấy một đoạn cho mỗi mô-đun, nhưng đó là cú pháp tốt hơn và được định hướng nhiều hơn trong tương lai.

Có rất nhiều tài nguyên khác mà bạn có thể xem trong trang tài liệu webpack mới về code splitting.

+1

Ngoài ra, với nhập khẩu động, chuỗi mẫu * có thể * được sử dụng trong đường dẫn mô-đun, chúng tôi chỉ cần đảm bảo cung cấp thông tin đường dẫn cho webpack (như bạn đã đề cập). –

+0

Có thực sự, tôi đã không precised rằng vì nó chỉ là (mát) es6 thay thế cho chuỗi concatenations. –

+0

chắc chắn. tôi không thấy bất kỳ đề cập đến chuỗi nối, vì vậy tôi nghĩ rằng tôi đề cập đến nó. –

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