使用Webpack创建单独的SPA包

Ada*_*kis 32 javascript webpack

如何在我的用户导航我的SPA时使用Webpack创建可能会或可能不会立即加载的独立SPA捆绑包?

我有一个联系人模块和一个任务模块.两者都有两个依赖关系.我希望WebPack为每个需要时(如果需要)加载的包创建包.

代码如下.问题似乎是这些条目中的每一个都被视为应用程序入口点,因此将webpack引导代码插入其中.

我已经看过各种各样的例子,CommonsChunkPlugin但是我找不到它的API参考/文档,而且从我可以猜测的,这不是我想要的.

编辑 - 在这里找到这些文档,并在我的编辑中添加了下面的插件尝试.


当前配置

module.exports = {
    entry: {
        contacts: './contacts',
        tasks: './tasks'
    },
    output: {
        path: path.resolve(__dirname, 'build'),
        filename: '[name]-bundle.js'
    }
};
Run Code Online (Sandbox Code Playgroud)

Contacts.js

define(['./ca', './cb'], function(ca, cb){
    var name = 'Contacts';
    alert(ca + ' ' + cb);
});
Run Code Online (Sandbox Code Playgroud)

Tasks.js

define(['./ta', './tb'], function(ta, tb){
    var name = 'TASKS Main';
    alert(ta + ' ' + tb);
});
Run Code Online (Sandbox Code Playgroud)

任务-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__));

/***/ }
/******/ ]);
Run Code Online (Sandbox Code Playgroud)

编辑

这是我使用CommonsChunkPlugin的第二次尝试.我创建了一个虚拟的app.js

app.js

var module = window.location.hash.split('/')[0];
alert(module);
Run Code Online (Sandbox Code Playgroud)

然后我将所有联系人和任务文件移动到组件文件夹下,否则将它们单独留下.我的新配置:

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'
        })
    ]
};
Run Code Online (Sandbox Code Playgroud)

很奇怪,现在app-bundle.js似乎没有任何Webpack引导代码

webpackJsonp([0,1,2],[
/* 0 */
/***/ function(module, exports) {

    var module = window.location.hash.split('/')[0];
    alert(module);

/***/ }
]);
Run Code Online (Sandbox Code Playgroud)

contacts-components-bundle.js现在只有这个

webpackJsonp([1,2],[]);
Run Code Online (Sandbox Code Playgroud)

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 = "";
/******/ })
/************************************************************************/
/******/ ([]);
Run Code Online (Sandbox Code Playgroud)

同样,我只是尝试使用Webpack来获取SPA概念证明并运行,使用某种根app.js入口点,然后根据需要加载一些任意数量的模块/组件.这对于requirejs来说非常简单,所以我不得不想象我在这里缺少一些关键点,尤其是我所见过的所有文章都在讨论Webpack对于SPA的好处.


编辑2

根据下面的bebraw答案,我尝试了以下方法:

app.js

var mod = window.location.hash.split('/')[0];
alert(mod);

require.ensure([], function() {
    require('./components/' + mod).show();
});
Run Code Online (Sandbox Code Playgroud)

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'
    }
};
Run Code Online (Sandbox Code Playgroud)

然后在我的构建文件夹中,我留下了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
        })
    ]
};
Run Code Online (Sandbox Code Playgroud)

产生与上面相同,但现在还有 tasks-component-bundle.js和contacts-component-bundle.js,它们都只有一些webpack引导代码; 任务和联系人代码都仍在1.1-bundle中.

同样,我只是希望能够以某种方式告诉Webpack将各个模块及其依赖项捆绑在一起,以便在需要时进行后续的延迟异步加载.

最终的答案由Tobias-Webpack创建者提供 - 我将在此为后人提供.

真正的动态是不可能的.webpack(在require.js的构造中)在执行之前编译您的应用程序,并且无权访问运行时信息.动态需要webpack潜入每个可能的文件夹,只要你的动态表达不包含...你甚至可以配置它使用mod +'/'+ mod与ContextReplacementPlugin和一点RegExp魔术(使用反向引用RegExp).默认情况下,它将包含太多模块.

Tob*_* K. 13

webpack为每个异步require语句(require.ensure或AMD require([]))创建一个分裂点.因此,您需要编写require([])应用程序的每个延迟加载部分.

您的SPA只有一个入口点:(客户端)路由器.我们称之为app.js.页面按需加载,不是入口点.

webpack.config.js:

module.exports = {
    entry: {
        app: './app'
    },
    output: {
        path: path.resolve(__dirname, 'build'),
        filename: '[name]-bundle.js'
    }
}
Run Code Online (Sandbox Code Playgroud)

app.js:

var mod = window.location.hash.split('/')[0].toLowerCase();
alert(mod);

switch(mod) {
    case "contacts":
        require(["./pages/contacts"], function(page) {
            // do something with "page"
        });
        break;
    case "tasks":
        require(["./pages/tasks"], function(page) {
            // do something with "page"
        });
        break;
}
Run Code Online (Sandbox Code Playgroud)

替代方案:使用"上下文".

使用动态依赖时i.e require("./pages/" + mod)你不能为每个文件写一个分割点.对于这种情况,有一个加载器包装require.ensure块中的文件:

app.js

var mod = window.location.hash.split('/')[0].toLowerCase();
alert(mod);

require("bundle!./pages/" + mod)(function(page) {
    // do something with "page"
});
Run Code Online (Sandbox Code Playgroud)

这是特定于webpack的.别忘了npm install bundle-loader --save.检查正确的外壳,它区分大小写.