webpack set the outputPath relative to the file where require occurs

Viewed 585

Is there a way to hint webpack to generate output files relative to the file where the generated file occurs as required? Suppose I have the following configuration:

let indexHTML = new HtmlWebpackPlugin({
    template: "./src/pug/index.pug",
    filename: 'index.html',
})

let iframeExample = new HtmlWebpackPlugin({
    template: "./src/pug/iframe-example.pug",
    filename: 'examples/index.html',
})

module.exports = merge(common, {
    mode: "development",
    output: {
        filename: "[name].bundle.js",
        path: path.join(__dirname, "/dist"),
    },
    entry: { 
        index: "./src/js/index.js",
    },
    plugins: [
        new CleanWebpackPlugin(), 
        indexHTML,
        iframeExample
    ],
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    { 
                        loader: 'file-loader',
                        options: {
                            name: "[name].[ext]",
                            outputPath: "css",
                            esModule: false,
                        } 
                    }
                ]
            },
            {
                test: /\.(svg|png|jpg|gif)$/,
                use: {
                    loader: "file-loader",
                    options: {
                        name: "[name].[ext]",
                        outputPath: "imgs",
                        esModule: false,
                    }
                }
            },
            {
                test: /\.(aac|mp3)$/,
                use: {
                    loader: "file-loader",
                    options: {
                        name: "[name].[ext]",
                        outputPath: "audio",
                        esModule: false
                    }
                }
            },
            {
                test: /\.(webm|mp4)$/,
                use: {
                    loader: "file-loader",
                    options: {
                        name: "[name].[ext]",
                        outputPath: "video",
                        esModule: false
                    }
                }
            },
        ]
    },
});

In this configuration, two html pages are generated by HtmlWebpackPlugin: one is 'dist/index.html' ('dist/' being my output folder) and the other is 'dist/examples/index.html' (that is 'index.html' in the 'examples/' folder, which HtmlWebpackPlugin will create for me).

When file-loader encounters a require/import statement in my generated html file, it will try to resolve it into a url and copy that file from my working folder structure into the output folder. In outputPath for the file-loader I have specified relative paths for the output content ("imgs", "video", etc.), which will be prefixed to every url produced by file-loader, resulting in relative urls in each corresponding html.

The problem is, the folders themselves will be generated in the output folder ('dist' in my case), and not where corresponding htmls occur in the output folder structure. That is, all .css files referenced in 'dist/examples/index.html' will be put into 'dist/css/' folder, and thus will not be seen in 'dist/examples/index.html', which contains only relative paths ('css/').

To reiterate my question: How do I make file-loader produce output files relative to the location where they are referenced? That is, I want file-loader to output any .css files referenced in 'dist/examples/index.html' to '/dist/examples/css/'.

1 Answers

You can make use of publicPath from webpack's output object,

module.exports = merge(common, {
    mode: "development",
    output: {
        filename: "[name].bundle.js",
        path: path.join(__dirname, "/dist"),
        publicPath: 'https://test.org/example/'
    },
..
..

The above change will allow both of the index.html files to have same relative path in production.

index.html

<script type="text/javascript" src="https://test.org/example/test.js"></script>

examples/index.html

<script type="text/javascript" src="https://test.org/example/test.js"></script>

For more on publicPath please refer to the answer https://stackoverflow.com/a/38748466/3679048

Related