Skip to content

loader.options.publicPath not being honored #222

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
4lph4-Ph4un opened this issue Jul 29, 2018 · 19 comments
Closed

loader.options.publicPath not being honored #222

4lph4-Ph4un opened this issue Jul 29, 2018 · 19 comments

Comments

@4lph4-Ph4un
Copy link

4lph4-Ph4un commented Jul 29, 2018

Hi!
If I haven't been mistaken, should the publicPath -option allow me to output generated bundles to the given destination?

My baseconfig has this as publicPath:

output: {
  publicPath: "/scripts/",
  path:       SCRIPT_DIR  // this points to "/public/scripts"
}

Then on my derived production config has:

if (TARGET_ENV === "production") 
  commonConfig = merge(commonConfig, {
    entry: {
      app: `${APP_DIR}/index.tsx`
    },
    output: {
	filename:      "[name].[chunkhash].js",
	chunkFilename: "[name].[chunkhash].js"
    },
    module: {
      rules: [
        {
          test: /\.css$/,
          use: [
            {
              loader: MiniCSSExtractPlugin.loader,
              options: {
                publicPath: "/styles/",
	      }
            },
            "css-loader?-url",
	    "postcss-loader"
        ]
    }
    plugins: [
      new WebpackChunkHashPlugin(),	// Hash from content (to output options)
      new HtmlWebpackPlugin({
        filename: "../index.html",
        title:    PROJECT_TITLE,
	template: `${APP_DIR}/index.ejs` 
      }),
      new InlineChunkManifestHtmlWebpackPlugin(),
      new MiniCSSExtractPlugin({ 
        filename:      "[name].[hash].css",
        chunkFileName: "[id].[hash].css" 
      })
    ]
});

I'm attempting to get a structure where JS goes to public/scripts/ and CSS public/styles.
JS ends up in the right place. The CSS doesn't seem to.

@freemagee
Copy link

I am also experiencing this. I try to break it down below, with my current solution.

Webpack output object

output: {
    path: path.resolve(__dirname, "./App/JavaScript"),
    publicPath: "/App/JavaScript/"
}

Loader object

{
  loader: MiniCssExtractPlugin.loader,
  options: {
    publicPath: "../bananas/"// As an example
  }
}

Finally, the plugin config

new MiniCssExtractPlugin({
  filename: "Styles.css"
})

This will generate the Styles.css at /App/JavaScript/. The expected folder "bananas" never gets created in /App/. If a relative path is put into the filename, it will generate the file in the correct location /App/bananas/Styles.css

new MiniCssExtractPlugin({
  filename: "../bananas/Styles.css"
})

@4lph4-Ph4un
Copy link
Author

I've also survived by putting the relative path in plugins filename. However I feel the publicPath -option should work? Also what is curious about the relative path -solution is that if I use html -templates that are generated from builds, the style src -paths there will contain the relative portion, which is a bit ugly. It's not a big issue, but would love to find a reasonably easy way to get rid of those! :)

@freemagee
Copy link

Yes, I have also seen the relative path looking a little ugly. My real world project looks like this:

<link href="/App/JavaScript/../StyleSheets/CSS/Styles.css" rel="stylesheet">

Again, I agree it is not a big issue and it does work this way.
I did look at the source code a bit yesterday in src/loader.js, line 37.

const publicPath =
    typeof query.publicPath === 'string'
      ? query.publicPath
: this._compilation.outputOptions.publicPath;
const outputOptions = {
    filename: childFilename,
    publicPath,
};

My only thought looking at it was that publicPath in outputOptions was not set as a property. I will amend my local NPM copy and see if it makes a difference.

@freemagee
Copy link

Nope, not that simple unfortunately!

@4lph4-Ph4un
Copy link
Author

Thanks for checking that out, regardless! :) I couldn't get some sleep so I checked somethings too. After testing older setup with older Webpack and extract-text-webpack-plugin, I noticed that doesn't seem to work either with publicPaths either! Seems we might've stumbled upon a bug that might've been in the internals longer and could be related to some other parts of the Webpack pipeline.

@michael-ciniawsky
Copy link
Member

I'm not sure I'm following, sometimes it seems publicPath is misunderstood as working in the same way as output.path for the mini-css-extract-plugin

webpack.config.js

...
output: {
    path: path.resolve(__dirname, 'app/'),
    publicPath: "app/" // http://localhost:3000
}
...
new MiniCssExtractPlugin({
  filename: "styles/styles.css" // Note the `styles/`
})
|– app // http://localhost:3000/
||– bundle.js // http://localhost:3000/bundle.js
||– styles
||| – style.css // http://localhost:3000/styles/styles.js
|
|– package.json
|– webpack.config.js

@4lph4-Ph4un
Copy link
Author

To be exact the issue is that I'm having comes into play in a structure like this:

├── public
│   ├── scripts
│   │   ├── *.js
│   ├── styles
│   │   ├── *.css
│   ├── index.html
output: {
  publicPath: "/scripts/",
  path:       SCRIPT_DIR    // This points to 'public/scripts'
},

What I'm inclining here is that I cannot seem to get any configuration where applying a loader.options.publicPath would actually point into the path alongside the scripts without applying an ugly...

new MiniCSSExtractPlugin({ 
  filename: "../styles/[name].[hash].css"
}),

...relative binding in the plugin, which then forms a path in the index.html as:

<link href="https://github.com/scripts/../styles/fileName.css" rel="stylesheet">

This works, and it's not the end of the world, but that relative part in production code kinda bugs me a bit. 😃 But if I have understood something wrong in my usage, please point that out!

@michael-ciniawsky
Copy link
Member

kk what is inlining the paths atm, the html-webpack-plugin ? The loader.options.publicPath might not be honored by the html-webpack-plugin or it gets overridden somewhere else, either case is definitely a bug

@michael-ciniawsky michael-ciniawsky added this to the 0.5.0 milestone Aug 24, 2018
@michael-ciniawsky michael-ciniawsky changed the title publicPath not outputting CSS -bundles to alternative location. loader.options.publicPath not being honored Aug 24, 2018
@4lph4-Ph4un
Copy link
Author

Yes, this definetely sounds like the case! Thank you so much for addressing this. 👍 I don't have a good spot to check right now, but I could try to check what difference removing html-webpack-plugin (and otherwise simplify the project to give more useful data about the issue) over the weekend if I get a good moment!

@michael-ciniawsky
Copy link
Member

kk 👍, if it is the html-webpack-plugin it shouldn't be hard to reproduce I will take a look into it once I have the time. Maybe filling an issue in html-webpack-plugin aswell would be a good idea

@yuchant
Copy link

yuchant commented Sep 2, 2018

@michael-ciniawsky I'm having the problem too, and I have a barebones setup with nothing mini-css-extract-plugin. File output is going to webpack.output which is typically JS related.

  module : {
    rules: [{
      test: /\.scss$/,
      use: [
        {
          loader: MiniCssExtractPlugin.loader,
          options: {
            publicPath: "../css/"
          }
        },
        "css-loader", // translates CSS into CommonJS
        "sass-loader" // compiles Sass to CSS, using Node Sass by default
      ]
    }]
  },

@sokra
Copy link
Member

sokra commented Sep 9, 2018

should the publicPath -option allow me to output generated bundles to the given destination?

No that's not the effect of the publicPath option.

Use filename and chunkFilename instead.

@jantimon
Copy link
Contributor

jantimon commented Oct 8, 2018

@sokra What would be the correct config to place the css inside a subfolder without being able to set a public path?

Relative paths inside the following example would just not work:

new MiniCSSExtractPlugin({ 
  filename: "css/[name].[hash].css"
}),

@sokra
Copy link
Member

sokra commented Oct 9, 2018

For this filename you probably need publicPath: "../" in the MCEP loader.

@jantimon
Copy link
Contributor

jantimon commented Oct 9, 2018

thanks @sokra I’ll tried that but this issue is about the problem that this seems to be broken - could you please post a small example for the loader + plugin configuration which would allow to generate the css file into a sub folder?

@hstaniszewski
Copy link

Besides that publicPath does not work I noticed another problem. My config looks something like this:

{
    entry: {
        'static/app': resolve('path/to/file/file.js')
        // other entries
    },
    output: {
        filename: '[name].js',
        path: resolve('/public')
    },
    module: {
        rules: [
            {
                test: /\.(sa|sc|c)ss$/,
                use: [
                    { loader: MiniCssExtractPlugin.loader }
                    // ...
                ]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: `/style/[name].css`
        })
    ]
}

File structure after build looks like this:

/public
    /static
        /style
            /static
                originalName.css

If i change /style/[name].css to /style/customName.css

The file structure after build looks like this:

/public
    /static
        /style
            customName.css

This means that in my case [name] contains a entry path and file name /static/originalName but should contain only the file name.

@jantimon
Copy link
Contributor

We are using publicPath:'../' for the scss-config-webpack-plugin just like @sokra proposed and it works. 👍

https://github.com/namics/webpack-config-plugins/blob/master/packages/scss-config-webpack-plugin/config/production.config.js#L26

@rhernandog
Copy link

Indeed @sokra suggestion works as @jantimon says:

use: [
  {
    loader: MiniCssExtractPlugin.loader,
    options: {
      publicPath: "../"
    }
  },
]

My setup is something like this:

/src
/dist
    /js
    /css
    /api
    index.html

Thanks @sokra !!!!

@alexander-akait
Copy link
Member

Fixed in master, now publicPath can be function for more complex setup

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants