【问题标题】:Webpack 2: shimming like RequireJS for jQWidgets?Webpack 2:像 RequireJS 一样为 jQWidgets 填充?
【发布时间】:2018-03-07 22:34:34
【问题描述】:

我正在从 RequireJS 项目迁移到 Webpack。 后者对我来说是新的,我将其用作学习练习。 在 RequireJS 我可以注册这样的东西:

shim: {
    'jqxcore': {
        exports: "$",
        deps: ["jquery"]
    },
    'jqxtree': {
        exports: "$",
        deps: ["jquery", "jqxcore"]
    },
    'jqxbutton': {
        exports: "$",
        deps: ["jquery", "jqxcore"]
    },
    'jqxsplitter': {
        exports: "$",
        deps: ["jquery", "jqxcore"]
    },
    'jqxmenu': {
        exports: "$",
        deps: ["jquery", "jqxcore"]
    }
}

然后只需要“jqxsplitter”,例如:

import "jqxsplitter"

并且东西将被正确注册和加载。 现在,我正在查看从 RequireJS 迁移到 Webpack 时发现的一些指南/教程/要点,例如 this 一个和 this 一个。 因此,根据这些见解,我正在我的 webpack.config.js 中尝试这样的事情:

"use strict";

// Required to form a complete output path
const path = require("path");

// Plagin for cleaning up the output folder (bundle) before creating a new one
const CleanWebpackPlugin = require("clean-webpack-plugin");

const HtmlWebpackPlugin = require("html-webpack-plugin");
const webpack = require("webpack");

// Path to the output folder
const bundleFolder = "./wwwroot/";

// Path to the app source code
const appFolder = "./app/";

module.exports = {
    // Application entry point
    entry: {
        main: appFolder + "index.ts",
        vendor: [
            "knockout",
            "jquery",
            "jqxcore"
        ],
        jqxsplitter: "jqxsplitter"
    },

    // Output file
    output: {
        filename: "[name].js",
        chunkFilename: "[name].js",
        path: path.resolve(bundleFolder)
    },
    module: {
        rules: [{
            test: /\.tsx?$/,
            loader: "ts-loader",
            exclude: /node_modules/
        }, {
            test: /\.html?$/,
            loader: "html-loader" //TODO: file-loader?
        }],
        loaders: [{
            test: /jqxcore/,
            loader: "imports?jquery!exports?$"
        }, {
            test: /jqxsplitter/,
            loader: "imports?jquery,jqxcore!exports?$"
        }]
    },
    resolve: {
        extensions: [".tsx", ".ts", ".js"],
        alias: {
            "jqxcore": "jqwidgets-framework/jqwidgets/jqxcore",
            "jqxsplitter": "jqwidgets-framework/jqwidgets/jqxsplitter"
        }
    },
    plugins: [
        new CleanWebpackPlugin([bundleFolder]),
        new HtmlWebpackPlugin({
            filename: "index.html",
            template: appFolder + "index.html",
            chunks: ["main", "vendor"]
        }),
        new webpack.optimize.CommonsChunkPlugin({
            name: "vendor",
            filename: "vendors.js",
            minChunks: Infinity
        })
    ],
    devtool: "source-map"
};

相关部分(我假设)是

module: {
    loaders: [{
        test: /jqxcore/,
        loader: "imports?jquery!exports?$"
    }, {
        test: /jqxsplitter/,
        loader: "imports?jquery,jqxcore!exports?$"
    }]
},

很清楚“imports/exports”的语法应该如何等同于 RequireJS 的“deps”和“exports”。 但是,当我在 index.ts 文件(应用程序根目录)中执行此操作时:

import "jqwidgets-framework/jqwidgets/jqxsplitter";

我在运行我的应用程序时收到“jqxBaseFramework is undefined”错误。 我在 jQWidgets 的论坛上找到了对这个错误的引用,但似乎没有一个答案真正解决了这个问题或包括 AOT 编译之类的东西,这不适用于我的情况,因为我没有使用 Angular。

我在 jQWidges 论坛上posted 有同样的问题,但到目前为止没有实际答案(现在持续两周),只有一个通用答案说我应该在 jqxwhateverplugin.js 之前加载 jqxcore.js。 嗯,是的,很明显,这就是我想要使用匀场来完成的。

有什么想法吗?

【问题讨论】:

    标签: javascript webpack requirejs amd shim


    【解决方案1】:

    好吧,我最终深潜并为自己解决了这个问题。 如果有人发现自己在同一条或类似的船上,这就是解决方案。

    如果你美化 jQWidgets 脚本文件 jqxcore.js,你会看到它创建了一个通常称为“jqxBaseFramework”的全局变量,它当然永远不会全局公开,只会在它自己的模块中公开。这就是问题所在。

    解决方法是使用这个配置:

    module: {
        rules: [{
            test: /jqxcore/,
            use: "exports-loader?jqxBaseFramework"
        }, {
            test: /jqxknockout/,
            use: ["imports-loader?jqxBaseFramework=jqxcore,ko=knockout", "exports-loader?jqxBaseFramework"]
        }, {
            test: /jqxsplitter/,
            use: "imports-loader?jqxBaseFramework=jqxknockout"
        }]
    },
    resolve: {
        ...
        alias: {
            "knockout": "knockout/build/output/knockout-latest",
            "jqxcore": "jqwidgets-framework/jqwidgets/jqxcore",
            "jqxknockout": "jqwidgets-framework/jqwidgets/jqxknockout",
            "jqxsplitter": "jqwidgets-framework/jqwidgets/jqxsplitter"
        }
    },
    

    我想一旦点击,这一切都是有道理的。 jqxcore 模块现在将导出同名的 jqxBaseFramework 变量。

    我添加了淘汰赛支持。 jqxknockout 期望两个全局变量正常工作:ko(knockout)和jqxBaseFramework。 所以现在我们告诉 webpack,每当加载 jqxknockout 时,它应该加载 jqxcore 模块并将其导出分配给名为“jqxBaseFramework”的模块局部变量,并加载淘汰模块并将其导出分配给名为“ko”的模块局部变量. 这实际上等同于在 jqxknockout.js 脚本之前添加以下代码:

    var jqxBaseFramework = require("jqxcore");
    var ko = require("knockout");
    

    脚本现在可以再次执行,因为找到了这两个变量。 我添加了导出加载器来导出相同的,但现在从 jqxknockout 处理/增强了 jqxBaseFramework 变量。

    jqxSplitter 通常只需要 jqxCore 即可工作,但我想始终将它与淘汰赛一起使用。因此,我没有从 jqxCore 为 jqxSplitter 导入 jqxBaseFramework,而是从 jqxKnockout 获取它,所以所有部分都已到位。 所以现在当我将此代码添加到我所在的任何文件时:

    import "jqwidgets-framework/jqwidgets/jqxsplitter";
    

    Webpack 将需要 jqxknockout 及其导出,即 jqxBaseFramework,而这又需要 jqxcore 和 knockout et voilà,整个事情都连接得很漂亮。

    希望这对某人有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-29
      • 2013-05-26
      • 1970-01-01
      • 2013-07-07
      • 1970-01-01
      • 2016-05-21
      • 2020-09-24
      • 2015-08-13
      相关资源
      最近更新 更多