Search code examples
javascriptwebpackrequireglobal-scope

WebPack: require a javascript file into global scope


How can I require() a vendor library into global scope (using the WebPack bundler)? Independently of the fact if it actually has any exports definitions or not. I just need to require a library so that some other scripts on a page could also be able to use it.

I have found a possible solution by using script-loader like:

require('script-loader!./some-vendor-library.js');

And everything works perfectly, but the key disadvantage of that solution is that included script is actually evaluated via eval() function: the vendor-library code is added to end bundle.js as a string (not as an actual code). Is there any similar solution the library to be included to the end-bundle as a code, but not as a string?

P.S. Sometimes I need to do it dynamically, so, I can not add this to a webpack's config.


Solution

  • Script-loader wraps included scripts into a string sadly, so you could evalutate it out using Blob or something similar. But I think you might want to try something else.

    First: Make sure your require("./path/to/a-neat-module.js") is actually pulling in the file. Go to your outputted bundle and sift through the code to confirm. If possible, use npm to install any libraries, so you can simply, and portably, just call require("a-neat-module")

    So how can I make my non-exported variables and functions exposed?

    You can't directly.

    In your entry files, calling this will make all exported variables, available dynamically in the ./js folder and subdirectories, exposed:

    function requireAll(requireContext) {
        return requireContext.keys().map(requireContext);
    }
    var jsModules = requireAll(require.context("./js", true, /\.js$/));
    

    Or if you have a specific module and global in mind:

    window["silly"] = require("./js/silly.js");
    window["$"] = window["jQuery"] = require("jquery");
    

    But if your files aren't exporting it's just adding size to your bundle. Just think about how the code is exported into your final bundle. It's all wrapped up, so any variables defined in the global scope become local to the wrapping function.

    So, that's where loaders and plugins like script-loader and globals-loader come in. They help preprocess your files to be available to you later.

    Besides those, I do not know of any plugins that'll help dynamically convert your non-exported code by translation. It may be worthwhile attempting to re-write some of them to support the modular format. I know this isn't great news, but it might be worthwhile to think about how long it'll take to make your javascript modular. Nearly every js library worth its salt functions with this design flow to avoid importation problems.

    Ps: Have you checked out the effects of ouput.libraryTarget: "this" in your config? Some people have had success with that.

    PPs: Have you checked out webpack-raw-bundler? It will paste your code into another file with the global scope preserved, but it will be in another file so you could run a post build to concat the two together at the end. I run this on a few frontend files so that their non-exported functions are available as if each of the files were included in their own <script> tags. You do have to be cautious about load times and method overloading, however.