thgh / rollup-plugin-css-only

Rollup plugin that bundles imported css
MIT License
116 stars 27 forks source link

What is the recommended way to output hashed CSS files? #25

Closed jonknowles closed 2 years ago

jonknowles commented 3 years ago

I naively assumed that patterns such as those used in the rollup output.entryFileNames option would work, so at first I tried this:

css({ output: 'bundle.[hash].css' })

but that wrote a filename without templating in the hash value. Then I tried css({ output: false }) and gave my rollup output config option an assetFileNames template string of 'bundle.[hash].[ext]' to see if rollup would pick it up and output it, but that did not work either.

In order to get this to work (sorta), I had to do this crazy custom function using the undocumented third argument to the output file function:

css({
    output: (css, styleNodes, bundle) => {
        const [ { fileName } = {} ] = Object.values(bundle);
        const transformedFileName = fileName.replace(/\.js$/, '.css');
        const outputpath = `${BUILD_DIR}${transformedFileName}`;
        fs.writeFileSync(outputpath, css);
    }
})

This is still wrong, since it's outputting the hash of the JS bundle, not the CSS bundle, but it might be good enough for now. Surely there has to be a better way, but either I am missing it in the documentation, or it is not documented.

thgh commented 3 years ago

It's probably related to fileName vs name: https://github.com/thgh/rollup-plugin-css-only/blob/master/src/index.js#L80

I think name can handle hashes.

jonknowles commented 3 years ago

So just to clarify, is this something that's expected to work or something that's not supported? I'm a new user of this plugin so I don't know quite what to expect.

thgh commented 3 years ago

It's not supported at this moment. I'm not aware of the idiomatic way to add hashes to filenames with rollup, so hopefully someone can help with it.

benmccann commented 3 years ago

I think you had it right in your last comment (https://github.com/thgh/rollup-plugin-css-only/issues/25#issuecomment-739978890). Just need to use name instead of fileName: https://rollupjs.org/guide/en/#thisemitfileemittedfile-emittedchunk--emittedasset--string. Then users that don't wanted hased filenames can specify that in assetFileNames: https://rollupjs.org/guide/en/#outputassetfilenames

3bl3gamer commented 3 years ago

Made this a-bit-dirty-haskish wrapper as a workaround:

function hashFixCSS(options) {
    const plugin = css(options)
    const original_generateBundle = plugin.generateBundle
    const name = options.output
    let source
    options.output = s => (source = s)
    plugin.generateBundle = function (opts, bundle) {
        original_generateBundle.call(this, opts, bundle)
        this.emitFile({ type: 'asset', name, source })
    }
    return plugin
}

export default {
    ...
    output: {
        ...
        assetFileNames: '[name].[hash][extname]',
    },
    plugins: [
        ...
        hashFixCSS({ output: 'styles.css' }),
    ]
}

It overrides generateBundle and sends a callback as plugin output option, which disables plugin default output. Then it calls emitFile with name argument (instead of current fileName) which in turn makes output file name to use assetFileNames rule.

thgh commented 2 years ago

In v4.1.0 there will be two options: name & fileName. These are combined with output.assetFileNames, so that will make the whole naming thing explicit.