Как использовать Webpack для создания независимых пакетов SPA, которые могут или не могут быть загружены "на лету", когда мой пользователь переводит мой SPA?
У меня есть модуль контактов и модуль задач. Оба имеют две зависимости. Я хочу, чтобы WebPack создавал пакеты для каждого, которые загружаются при необходимости (и если).
Код ниже. Проблема заключается в том, что каждая из этих записей рассматривается как точки входа в приложение, и поэтому в нее вставлен код начальной загрузки webpack.
Я видел различные примеры с CommonsChunkPlugin
, но я не могу найти для него ссылку на API/документацию, и из того, что я могу догадаться, это не то, что я хочу в любом случае.
Изменить - нашел те документы здесь и добавил попытку с этим плагином ниже в моем редактировании.
Текущая конфигурация
module.exports = {
entry: {
contacts: './contacts',
tasks: './tasks'
},
output: {
path: path.resolve(__dirname, 'build'),
filename: '[name]-bundle.js'
}
};
Contacts.js
define(['./ca', './cb'], function(ca, cb){
var name = 'Contacts';
alert(ca + ' ' + cb);
});
Tasks.js
define(['./ta', './tb'], function(ta, tb){
var name = 'TASKS Main';
alert(ta + ' ' + tb);
});
Задания bundle.js
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(3), __webpack_require__(4)], __WEBPACK_AMD_DEFINE_RESULT__ = function(ta, tb){
var name = 'TASKS Main';
alert(ta + ' ' + tb);
}.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 1 */,
/* 2 */,
/* 3 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){
var name = 'TASKS - A';
alert('ta');
}.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 4 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){
var name = 'TASKS - B';
alert('tb');
}.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ }
/******/ ]);
ИЗМЕНИТЬ
Здесь моя попытка № 2 с CommonsChunkPlugin. Я создал фиктивный app.js
app.js
var module = window.location.hash.split('/')[0];
alert(module);
Затем я переместил все мои файлы контактов и задач в папку компонентов, но в остальном оставил их в покое. Моя новая конфигурация:
module.exports = {
entry: {
app: './app'
},
output: {
path: path.resolve(__dirname, 'build'),
filename: '[name]-bundle.js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: './components/contacts',
filename: 'contacts-component-bundle.js'
}),
new webpack.optimize.CommonsChunkPlugin({
name: './components/tasks',
filename: 'tasks-component-bundle.js'
})
]
};
В Bizarely теперь app-bundle.js, похоже, не имеет кода начальной загрузки Webpack
webpackJsonp([0,1,2],[
/* 0 */
/***/ function(module, exports) {
var module = window.location.hash.split('/')[0];
alert(module);
/***/ }
]);
contacts-components-bundle.js теперь просто имеет этот
webpackJsonp([1,2],[]);
и tasks-components-bundle.js, похоже, есть весь мой загрузочный код webpack
/******/ (function(modules) { // webpackBootstrap
/******/ // install a JSONP callback for chunk loading
/******/ var parentJsonpFunction = window["webpackJsonp"];
/******/ window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules) {
/******/ // add "moreModules" to the modules object,
/******/ // then flag all "chunkIds" as loaded and fire callback
/******/ var moduleId, chunkId, i = 0, callbacks = [];
/******/ for(;i < chunkIds.length; i++) {
/******/ chunkId = chunkIds[i];
/******/ if(installedChunks[chunkId])
/******/ callbacks.push.apply(callbacks, installedChunks[chunkId]);
/******/ installedChunks[chunkId] = 0;
/******/ }
/******/ for(moduleId in moreModules) {
/******/ modules[moduleId] = moreModules[moduleId];
/******/ }
/******/ if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules);
/******/ while(callbacks.length)
/******/ callbacks.shift().call(null, __webpack_require__);
/******/ if(moreModules[0]) {
/******/ installedModules[0] = 0;
/******/ return __webpack_require__(0);
/******/ }
/******/ };
/******/ // The module cache
/******/ var installedModules = {};
/******/ // object to store loaded and loading chunks
/******/ // "0" means "already loaded"
/******/ // Array means "loading", array contains callbacks
/******/ var installedChunks = {
/******/ 2:0,
/******/ 1:0
/******/ };
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // This file contains only the entry chunk.
/******/ // The chunk loading function for additional chunks
/******/ __webpack_require__.e = function requireEnsure(chunkId, callback) {
/******/ // "0" is the signal for "already loaded"
/******/ if(installedChunks[chunkId] === 0)
/******/ return callback.call(null, __webpack_require__);
/******/ // an array means "currently loading".
/******/ if(installedChunks[chunkId] !== undefined) {
/******/ installedChunks[chunkId].push(callback);
/******/ } else {
/******/ // start chunk loading
/******/ installedChunks[chunkId] = [callback];
/******/ var head = document.getElementsByTagName('head')[0];
/******/ var script = document.createElement('script');
/******/ script.type = 'text/javascript';
/******/ script.charset = 'utf-8';
/******/ script.async = true;
/******/ script.src = __webpack_require__.p + "" + chunkId + "." + ({"0":"app","1":"./components/contacts"}[chunkId]||chunkId) + "-bundle.js";
/******/ head.appendChild(script);
/******/ }
/******/ };
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ })
/************************************************************************/
/******/ ([]);
Опять же, я просто пытаюсь использовать Webpack, чтобы получить доказательство API о концепции и запуске, с некоторой точкой входа root.js, а затем некоторое количество модулей/компонентов, которые загружаются по требованию. Это просто тривиально с требованием, поэтому я должен представить себе, что у меня отсутствует что-то здесь, особенно со всеми статьями, которые я видел, говоря о том, как большой Webpack для SPA.
РЕДАКТИРОВАТЬ 2
В ответе на bebraw ниже я пробовал следующее:
app.js
var mod = window.location.hash.split('/')[0];
alert(mod);
require.ensure([], function() {
require('./components/' + mod).show();
});
webpack.config.js
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: {
app: './app'
},
output: {
path: path.resolve(__dirname, 'build'),
filename: '[name]-bundle.js'
}
};
И затем в моей папке сборки я остался с app-bundle.js, у которого есть весь мой код начальной загрузки, и мой код app.js, а затем 1.1-bundle.js, который имеет все моих заданий и кода контактов.
Я также пробовал это
module.exports = {
entry: {
app: './app'
},
output: {
path: path.resolve(__dirname, 'build'),
filename: '[name]-bundle.js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: './components/contacts',
filename: 'contacts-component-bundle.js',
children: true
}),
new webpack.optimize.CommonsChunkPlugin({
name: './components/tasks',
filename: 'tasks-component-bundle.js',
children: true
})
]
};
Это дает то же самое, что и выше, но теперь также имеет task-component-bundle.js и contacts-component-bundle.js, оба из которых имеют только некоторый код начальной загрузки webpack; задачи и код контактов все еще находятся в 1.1-пакете.
Опять же, я просто хочу сказать Webpack, так или иначе, связать отдельные модули и их зависимости для последующей ленивой асинхронной загрузки, когда это необходимо.
Окончательный ответ дал создатель Тобиаса-Вебпака - ниже, который я положу сюда для потомков.
Истинная динамика невозможна. webpack (в constract to require.js) компилирует ваше приложение перед его исполнением и не имеет доступа к информации о времени выполнения. Dynamic требует погружения в webpack в каждую возможную папку, поскольку ваше динамическое выражение не содержит... Вы даже можете настроить его на использование mod + '/' + mod с помощью ContextReplacementPlugin и немного волшебства RegExp (используйте обратные ссылки в RegExp). По умолчанию в него будет включено слишком много модулей.