简体   繁体   中英

How can I transform custom content into a javascript module in webpack?

I have a custom format that I want to transform into Javascript, so it can be imported in my React app. The details of this transformation are already solved and not important.

To accomplish this, I wrote a custom loader that performs the transformation (really, shells out to the executable that does the transformation). This part seems to work great!

var child_process = require('child_process');

module.exports = function(source) {
    const callback = this.async();

    const exepath = "..\\xml-converter\\xml-converter\\bin\\debug\\xml-converter.exe"

    const child = child_process.exec(exepath, { shell: false }, function(error, stdout, stderr) {
        return callback(error, stdout);
    });

    child.stdin.write(source);
    child.stdin.end();
}

I've added it to webpack, and I know it's being used.

//...
module: {
    rules: [
        //...other rules...
        {
            test: /\.xml$/,
            use: [
                {  //more on this later
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                    }
                },
                {
                    loader: path.resolve(__dirname, 'room_loader.js')
                }
            ]
        }
    ]
}

And then, I try and use this loader in code:

import myAwesomeData from './myData.xml'

console.log(myAwesomeData.aPropertyThatIsDefinitelyThere)
console.log(myAwesomeData)

This outputs:

undefined
/static/media/myData.05d816d8.xml

Rather than giving me my javascript, it's treating it like an image or something and returning javascript that builds the URL to it. If I load the provided URL manually, I get the expected source code:

export let myAwesomeData = {
    aPropertyThatIsDefinitelyThere: "whatever..."
}

However, this is obviously not what I want.

I tried chaining the babel loader into the equation (see above), and while it functioned (correctly transpiling the code), it didn't solve the core problem.

Is what I'm trying to do possible? If so, how?

So, I oversimplified my problem statement, and as a result my question was not about what I thought it was.

I am using create-react-app , but that doesn't supposed customizing Webpack the way I needed (loading a custom loader), so I added react-app-rewired . I then added this in my customization file:

module.exports = function override(config, env) {
    config.module.rules.push({
        test: /\.xml$/,
        use: [
        {
            loader: path.resolve(__dirname, 'room_loader.js')
        }]
    });

    return config;
};

However, a close examination of the predefined rules (most easily done by ejecting, but you might be able to dig them up somewhere else) shows that this is not correct. The correct place to put them is within the third rule, which has a list of sub rules that ends with a general "we don't know how to handle this, so we'll treat it like an image" loader.

Thus what you really want to do is:

module.exports = function override(config, env) {
    var rules = config.module.rules[2].oneOf;

    var position = rules.length - 2;

    rules.splice(position, 0, {
        test: /\.xml$/,
        use: [
        {
            loader: path.resolve(__dirname, 'room_loader.js')
        }]
    });

    return config;
};

This works great, and was a lot easier than I thought it was going to be.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM