javascript 如何使用 webpack 从控制台 require()?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29223071/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 10:14:55  来源:igfitidea点击:

How do I require() from the console using webpack?

javascriptecmascript-6webpack

提问by Seth

How do I require() / import modules from the console? For example, say I've installed the ImmutableJS npm, I'd like to be able to use functions from the module while I'm working in the console.

如何从控制台 require() / 导入模块?例如,假设我已经安装了 ImmutableJS npm,我希望能够在我在控制台中工作时使用模块中的函数。

采纳答案by Rene Hamburger

Here's another more generic way of doing this.

这是另一种更通用的方法。

Requiring a module by ID

通过 ID 要求模块

The current version of WebPack exposes webpackJsonp(...), which can be used to require a module by ID:

当前版本的 WebPack 公开webpackJsonp(...),可用于通过 ID 要求模块:

function _requireById(id) {
  return webpackJsonp([], null, [id]);
}

or in TypeScript

或在打字稿中

window['_requireById'] =
  (id: number): any => window['webpackJsonp'];([], null, [id]);

The ID is visible at the top of the module in the bundled file or in the footer of the original source file served via source maps.

该 ID 在捆绑文件的模块顶部或通过源映射提供的原始源文件的页脚中可见。

Requiring a module by name

按名称要求模块

Requiring a module by name is much trickier, as WebPack doesn't appear to keep any reference to the module path once it has processed all the sources. But the following code seems to do the trick in lot of the cases:

按名称要求模块要复杂得多,因为 WebPack 处理完所有源后似乎不会保留对模块路径的任何引用。但在很多情况下,以下代码似乎可以解决问题:

/**
 * Returns a promise that resolves to the result of a case-sensitive search
 * for a module or one of its exports. `makeGlobal` can be set to true
 * or to the name of the window property it should be saved as.
 * Example usage:
 *   _requireByName('jQuery', '$');
 *   _requireByName('Observable', true)′;
 */
window['_requireByName'] =
  (name: string, makeGlobal?: (string|boolean)): Promise<any> =>
    getAllModules()
    .then((modules) => {
      let returnMember;
      let module = _.find<any, any>(modules, (module) => {
        if (_.isObject(module.exports) && name in module.exports) {
          returnMember = true;
          return true;
        } else if (_.isFunction(module.exports) &&
                   module.exports.name === name) {
          return true;
        }
      });
      if (module) {
        module = returnMember ? module.exports[name] : module.exports;
        if (makeGlobal) {
          const moduleName = makeGlobal === true ? name : makeGlobal as string;
          window[moduleName] = module;
          console.log(`Module or module export saved as 'window.${moduleName}':`,
            module);
        } else {
          console.log(`Module or module export 'name' found:`, module);
        }
        return module;
      }
      console.warn(`Module or module export '${name}'' could not be found`);
      return null;
    });

// Returns promise that resolves to all installed modules
function getAllModules() {
  return new Promise((resolve) => {
    const id = _.uniqueId('fakeModule_');
    window['webpackJsonp'](
      [],
      {[id]: function(module, exports, __webpack_require__) {
        resolve(__webpack_require__.c);
      }},
      [id]
    );
  });
}

This is quick first shot at this, so it's all up for improvement!

这是快速的第一枪,所以一切都需要改进!

回答by psimyn

Including this in a module will allow require([modules], function)to be used from a browser

将此包含在模块中将允许require([modules], function)从浏览器中使用

window['require'] = function(modules, callback) {
  var modulesToRequire = modules.forEach(function(module) {
    switch(module) {
      case 'immutable': return require('immutable');
      case 'jquery': return require('jquery');
    }
  })
  callback.apply(this, modulesToRequire);
}

Example Usage:

示例用法:

require(['jquery', 'immutable'], function($, immutable) {
  // immutable and $ are defined here
});

Note:Each switch-statement option should either be something this module already requires, or provided by ProvidePlugin

注意:每个 switch-statement 选项应该是这个模块已经需要的东西,或者由 ProvidePlugin 提供



Sources:

资料来源:

Based on this answer, which can be used to add an entire folder.

基于此答案,可用于添加整个文件夹。

Alternative method from Webpack Docs- which allows something like require.yourModule.function()

来自Webpack Docs 的替代方法- 它允许类似require.yourModule.function()

回答by Paul Whipp

Being able to use requiremodules in the console is handy for debugging and code analysis. @psimyn's answer is very specific so you aren't likely to maintain that function with all the modules you might need.

能够require在控制台中使用模块对于调试和代码分析非常方便。@ psimyn的回答非常具体,因此您不太可能使用您可能需要的所有模块来维护该功能。

When I need one of my own modules for this purpose, I assign a window property to it so I can get at it e.g window.mymodule = whatever_im_exporting;. I use the same trick to expose a system module if I want to play with it e.g:

当我为此需要一个自己的模块时,我为它分配了一个 window 属性,这样我就可以得到它,例如window.mymodule = whatever_im_exporting;. 如果我想使用它,我使用相同的技巧来公开系统模块,例如:

myservice.js:

我的服务.js:

let $ = require('jquery');
let myService = {};

// local functions service props etc...

module.exports = myService;

// todo: remove these window prop assignments when done playing in console
window.$ = $;
window.myService = myService;

It is still a bit of a pain, but digging into the bundles, I can't see any way to conveniently map over modules.

这仍然有点痛苦,但是深入研究包,我看不到任何方便地映射模块的方法。

回答by Venryx

I found a way that works, for both WebPack 1 and 2. (as long as the source is non-minified)

我找到了一种适用于 WebPack 1 和 2 的方法。(只要源未缩小)

Repo: https://github.com/Venryx/webpack-runtime-require

回购:https: //github.com/Venryx/webpack-runtime-require

Install

安装

npm install --save webpack-runtime-require

Usage

用法

First, require the module at least once.

首先,至少需要一次模块。

import "webpack-runtime-require";

It will then add a Require() function to the window object, for use in the console, or anywhere in your code.

然后它会向 window 对象添加一个 Require() 函数,以便在控制台或代码中的任何地方使用。

Then just use it, like so:

然后使用它,就像这样:

let React = Require("react");
console.log("Retrieved React.Component: " + React.Component);

It's not very pretty (it uses regexes to search the module wrapper functions) or fast (takes ~50ms the first call, and ~0ms after), but both of these are perfectly fine if it's just for hack-testing in the console.

它不是很漂亮(它使用正则表达式来搜索模块包装函数)或速度很快(第一次调用大约需要 50 毫秒,之后大约需要 0 毫秒),但是如果只是为了在控制台中进行黑客测试,这两者都非常好。

Technique

技术

The below is a trimmed version of the source to show how it works. (see the repo for the full/latest)

下面是源代码的修剪版本,以展示它是如何工作的。(有关完整/最新版本,请参阅 repo)

var WebpackData;
webpackJsonp([],
    {123456: function(module, exports, __webpack_require__) {
        WebpackData = __webpack_require__;
    }},
    [123456]
);

var allModulesText;
var moduleIDs = {};
function GetIDForModule(name) {
    if (allModulesText == null) {
        let moduleWrapperFuncs = Object.keys(WebpackData.m).map(moduleID=>WebpackData.m[moduleID]);
        allModulesText = moduleWrapperFuncs.map(a=>a.toString()).join("\n\n\n");

        // these are examples of before and after webpack's transformation: (which the regex below finds the var-name of)
        //      require("react-redux-firebase") => var _reactReduxFirebase = __webpack_require__(100);
        //      require("./Source/MyComponent") => var _MyComponent = __webpack_require__(200);
        let regex = /var ([a-zA-Z_]+) = __webpack_require__\(([0-9]+)\)/g;
        let matches = [];
        let match;
        while (match = regex.exec(allModulesText))
            matches.push(match);

        for (let [_, varName, id] of matches) {
            // these are examples of before and after the below regex's transformation:
            //      _reactReduxFirebase => react-redux-firebase
            //      _MyComponent => my-component
            //      _MyComponent_New => my-component-new
            //      _JSONHelper => json-helper
            let moduleName = varName
                .replace(/^_/g, "") // remove starting "_"
                .replace(new RegExp( // convert chars where:
                          "([^_])"      // is preceded by a non-underscore char
                        + "[A-Z]"       // is a capital-letter
                        + "([^A-Z_])",  // is followed by a non-capital-letter, non-underscore char
                    "g"),
                    str=>str[0] + "-" + str[1] + str[2] // to: "-" + char
                )
                .replace(/_/g, "-") // convert all "_" to "-"
                .toLowerCase(); // convert all letters to lowercase
            moduleIDs[moduleName] = parseInt(id);
        }
    }
    return moduleIDs[name];
}

function Require(name) {
    let id = GetIDForModule(name);
    return WebpackData.c[id].exports;
}

回答by Venryx

After making an npm module for this (see my other answer), I did a search on npms.io and seem to have found an existing webpack-plugin available for this purpose.

在为此制作了一个 npm 模块后(请参阅我的其他答案),我在 npms.io 上进行了搜索,似乎找到了一个可用的现有 webpack 插件。

Repo: https://www.npmjs.com/package/webpack-expose-require-plugin

回购:https: //www.npmjs.com/package/webpack-expose-require-plugin

Install

安装

npm install --save webpack-expose-require-plugin

Usage

用法

Add the plugin to your webpack config, then use at runtime like so:

将插件添加到您的 webpack 配置中,然后在运行时使用,如下所示:

let MyComponent = require.main("./path/to/MyComponent");
console.log("Retrieved MyComponent: " + MyComponent);

See package/repo readme page for more info.

有关更多信息,请参阅包/存储库自述页面。

EDIT

编辑

I tried the plugin out in my own project, but couldn't get it to work; I kept getting the error: Cannot read property 'resource' of undefined. I'll leave it here in case it works for other people, though. (I'm currently using the solution mentioned above instead)

我在自己的项目中尝试了该插件,但无法使其正常工作;我一直收到错误:Cannot read property 'resource' of undefined。不过,我会把它留在这里,以防它对其他人有用。(我目前正在使用上面提到的解决方案)

回答by Venryx

After both making my own npm package for this (see here), as well as finding an existing one (see here), I also found a way to do it in one-line just using the built-in webpack functions.

在为此制作了我自己的 npm 包(请参阅此处)以及找到现有的 npm 包(参阅此处)之后,我还找到了一种仅使用内置 webpack 函数在一行中完成的方法。

It uses WebPack "contexts": https://webpack.github.io/docs/context.html

它使用 WebPack“上下文”:https: //webpack.github.io/docs/context.html

Just add the following line to a file directly in your "Source" folder:

只需将以下行直接添加到“源”文件夹中的文件中:

window.Require = require.context("./", true, /\.js$/);

Now you can use it (eg. in the console) like so:

现在你可以像这样使用它(例如在控制台中):

let MyComponent = Require("./Path/To/MyComponent");
console.log("Retrieved MyComponent: " + MyComponent);

However, one important drawback of this approach, as compared to the two solutions mentioned above, is that it seems to not work for files in the node_modules folder. When the path is adjusted to "../", webpack fails to compile -- at least in my project. (perhaps because the node_modules folder is just so massive)

但是,与上述两种解决方案相比,这种方法的一个重要缺点是它似乎不适用于 node_modules 文件夹中的文件。当路径调整为“../”时,webpack 无法编译——至少在我的项目中是这样。(可能是因为 node_modules 文件夹太大了)

回答by lcharbon

Adding the below code to one of your modules will allow you to load modules by id.

将以下代码添加到您的模块之一将允许您按 id 加载模块。

window.require = __webpack_require__;

In the console use the following:

在控制台中使用以下内容:

require(34)

回答by Milan Jaros

You could do something similar as psimynadvised by adding following code to some module in bundle:

您可以通过将以下代码添加到捆绑包中的某个模块来执行类似于psimyn建议的操作:

require.ensure([], function () {
    window.require = function (module) {
        return require(module);
    };
});

Use require from console:

从控制台使用 require:

require("./app").doSomething();

See more

查看更多

回答by Ovidiu S.

expose-loaderis, in my opinion, a more elegant solution:

在我看来,expose-loader是一个更优雅的解决方案:

require("expose-loader?libraryName!./file.js");
// Exposes the exports for file.js to the global context on property "libraryName".
// In web browsers, window.libraryName is then available.