2

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/'.

Graham
  • 7,431
  • 18
  • 59
  • 84
user3808059
  • 373
  • 2
  • 15

1 Answers1

0

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

Danish
  • 497
  • 5
  • 14
  • I'm sure it won't change how file-loader treats those files. They still will be emitted directly to the output directory without taking the html's location into account. I don't want to change relative links, I want to tell file-loader to emit referenced files (.css, images, video files, etc) into some directory relative to the html. – user3808059 Jun 15 '20 at 18:42
  • hmm, it seems to me you could make use of [CopyWebpackPlugin](https://webpack.js.org/plugins/copy-webpack-plugin/) ? – Danish Jun 15 '20 at 19:18
  • 1
    I could, I think. But it would force me to change my current source folder structure, to create a bunch of new folders for every corresponding folder in the output folder, and for each type of content so that CopyWebpack could locate files, and then add CopyWebpack patterns for each one them. Apparently it doesnt take special function syntax to determine 'from' and 'to' in patterns, nor does it support matching patterns for globs other than ** and *, so I can only use string literals, resulting in too much boilerplate configuration code, if I had to have complex folder structure in the output. – user3808059 Jun 15 '20 at 21:33