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.
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"
})
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! :)
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.
Nope, not that simple unfortunately!
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.
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
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="/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!
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
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!
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
@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
]
}]
},
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.
@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"
}),
For this filename you probably need publicPath: "../" in the MCEP loader.
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?
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.
We are using publicPath:'../' for the scss-config-webpack-plugin just like @sokra proposed and it works. ๐
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 !!!!
Fixed in master, now publicPath can be function for more complex setup
Most helpful comment
I am also experiencing this. I try to break it down below, with my current solution.
Webpack output object
Loader object
Finally, the plugin config
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