Presidenten
Presidenten

Reputation: 6437

How to dynamically create a new file that should be included in the bundle with webpack?

I want to modify my webpack config with a custom middleware or loader that helps me by:

This is a simplified usecase of what I actually need, but if I know how to do this, I can solve the rest myself.

Any ideas?

Upvotes: 2

Views: 5764

Answers (3)

woojoo666
woojoo666

Reputation: 7921

this is SUPER late but in case anybody else lands here, I think the best way to solve this would be to generate a separate asset for every srv.js file, which can be done with a simple loader like so. You can then use these assets in your html just like you would include any other css or js file.

However, if you really want to only generate a single asset, you can do it like so:

  1. create a plugin that injects a function to the loader context, so the loaders can pass info back to the plugin (more info)
  2. create a loader for srv.js files that extracts the data and passes it to the plugin from step 1
  3. using the same plugin from step 1, aggregate all the data from the loaders and generates a single asset file (more info)

some rough code to show what I mean:

Plugin

class MyPlugin {
    apply(compiler) {
        var allData = "";

        // inject a function to loaderContext so loaders can pass back info
        compiler.hooks.compilation.tap('MyPlugin', compilation =>
            compilation.hooks.normalModuleLoader.tap(
                'MyPlugin',
                (loaderContext, module) => {
                    loaderContext.myExportFn = (data) => {
                        allData += data;
                    }
                }
            )
        );

        // at the end, generate an asset using the data
        compiler.hooks.emit.tapAsync(
            'MyPlugin',
            (compilation, callback) => {
                compilation.assets['myfile.js'] = {
                    source: () => allData,
                    size: () => allData.length
                };
                callback();
            }
        );
    }
}

Loader

module.exports = function(content) {
    // use the injected function, pass back some data
    this.myExportFn(`loader called for filepath: ${this.resourcePath}`);
    return content; // return the source file unchanged
};

Upvotes: 4

Presidenten
Presidenten

Reputation: 6437

So I came up with a solution that I suppose is good enough.

First I clean/create a file through a plugin that is run on script startup. Then I found out that loaders can see the filepath of the current processing file with this.resourcePath, so I just let a loader in preload insert import/export statements into the new file I just created.

This file is included in my main. Works like a charm. ...but its not strictly in memory and it doesnt handle removed/renamed files. But close enough!

Example code here: https://github.com/presidenten/vuex-automator-loader

Upvotes: 0

Nick Ribal
Nick Ribal

Reputation: 2109

I don't think there's a webpack way to do what you're describing. However, it seems like you can do that easily via a shell script, possibly using an npm script.

I have a similar use case at work: we use font-custom to generate Sass mixins into a (.gitignore'd file) _generated-font.scss file (from a directory of SVG files) and then import _generated-font.scss from a versioned Sass file, which is then picked up by webpack's sass-loader.

This obviously has to happen before webpack is run, so we run it via a prestart npm script.

I hope I'm clear enough - let me know otherwise :).

Upvotes: 0

Related Questions