We have several widgets that we want people to embed, similar to how you can embed your Twitter feed on your website using a placeholder element and their script:
<script src="https://platform.twitter.com/widgets.js"></script>
Is there a way you can disable fingerprints on certain JS files, as you wouldn't want people to update the path on their embed code every time you deploy your project? When using sprockets, we got around that using a deploy script which would find the JS file with the fingerprint and create a symlink to it without said fingerprint in production, while using the regular path in development. We still use this solution, but because webpacker uses fingerprints in dev, it makes development a royal PITA, as every little change also changes the fingerprint, and I have to update it in my external test projects for every little change.
We use a custom Webpack plugin to emit non-digest urls for all our assets. Perhaps this would help:
// Custom Webpack plugin
// Emits assets with hashed filenames as non-digest filenames as well
//
// Adding to end of plugins list ensures that all previously emitted hashed
// assets will be registered prior to executing the NonDigestAssetsPlugin.
function NonDigestAssetsPlugin() {}
const CHUNKHASH_REGEX = /(-[a-z0-9]{20}\.{1}){1}/;
NonDigestAssetsPlugin.prototype.apply = function(compiler) {
compiler.plugin('emit', function(compilation, callback) {
// Explore each compiled asset in build output:
Object.entries(compilation.assets).forEach(function([filename, asset]) {
if (!CHUNKHASH_REGEX.test(filename)) return;
// only for filenames matching CHUNKHASH_REGEX
const nonDigestFilename = filename.replace(CHUNKHASH_REGEX, '.');
compilation.assets[nonDigestFilename] = asset;
});
callback();
});
};
module.exports = NonDigestAssetsPlugin;
const environment = require('./environment');
// ...
environment.plugins.append('NonDigestAssetsPlugin', new NonDigestAssetsPlugin());
@rossta Thanks! I'll try that.
I've now published an updated version of the plugin above^^ on npm. More work is needed to make it configurable, but it's a start: https://www.npmjs.com/package/non-digest-webpack-plugin
We recently upgraded an app from Rails 4.2 to Rails 5.2 with Webpacker. We were using this gem with the Asset Pipeline: https://github.com/alexspeller/non-stupid-digest-assets. It allowed a white list of files to be generated without hashes.
We have a particular JS file that has hardcoded references so we can't change the file name or location. We are now generating that JS file via Webpack so it ends up in /public/packs with a cache-busting hash in the filename. For this particular file, after the pack files are generated, I need to remove the hash from the file name and copy it back to the previous /public/assets location.
I'm pretty new to Webpack. Would the NonDigestAssetsPlugin above be able to be customized to do that? Any other suggestions? Thanks in advance.
@rossta 's plugin has been working great for us for a while, but it doesn't work for CSS assets with the new webpacker.yml extract_css: true flag.
Would love to see something like a webpacker.yml pack_non_digest: true flag that also works with CSS, as we have a use case to publicly link to our generated assets.
@briansage, I am running into this same behavior with @rossta's plugin - do you have a current strategy (kludge even) for removing fingerprints from CSS filenames?
FWIW, I upgraded to webpacker 4 RC and added https://webpack.js.org/plugins/mini-css-extract-plugin/ adding the following to config/webpack/environment.js:
environment.plugins.append(
'MiniCssExtractPlugin',
new MiniCssExtractPlugin({ filename: 'css/[name].css' })
);
The current kludge is to use Guard to watch for changes in public/packs/manifest.json. Once that file updates, we run the assets:precompile task. It's not elegant, and it takes _forever_ to compile, but it's also the path of least surprise and works for now.
@jlw's solution works if you want to disable fingerprinting for all of your CSS files. In my case however, I only want to generate a fingerprint-less file for one of my stylesheets/packs. Does anyone have a suggestion on how to apply a module rule test as described here? https://github.com/webpack-contrib/mini-css-extract-plugin#minimal-example.
Also, this solution causes the app's stylesheet_pack_tag to link to the static asset which certainly wasn't my intention. The manifest lists both the fingerprinted as well as the non-fingerprinted files though.
Does anybody know of a way to generate a non-fingerprinted variation of a stylesheet?
I haven't tested this too much but you should be able to achieve this using a simple webpack config.
// inside of config/webpack/environment.js
const { environment } = require("@rails/webpacker");
environment.config.set("output.filename", chunkData => {
// if the name of the pack is "widget" then exclude the chunk hash
if (chunkData.chunk.name === "widget") return "widget.js";
// otherwise fingerprint the asset
return "[name].[chunkhash].js";
});
module.exports = environment;
I get "configuration.output.filename should be a string." with @thomascullen's solution.
For webpacker below to v4, (webpack 3),
I add three things:
// in config/webpack/custom.js file
const webpack = require('webpack')
const NonDigestPlugin = require('non-digest-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
module.exports = {
devtool: 'cheap-module-source-map',
plugins: [
new NonDigestPlugin(),
new ExtractTextPlugin('[name].css'),
]
}
If anyone else is looking at this using Webpacker v4 (for Rails 6), @thomascullen 's solution worked for me just fine for selectively not-digesting stuff, and doesn't need the plugin or anything. Thanks Thomas!
Here's how I solved this:
config/webpack/environment.jsenvironment.config.set('output.filename', chunkData => {
if (chunkData.chunk.name === 'widgets') return 'js/widgets.js';
return 'js/[name]-[contenthash].js';
});
environment.plugins.append(
'MiniCssExtractPlugin',
new MiniCssExtractPlugin({
moduleFilename: chunkData => {
if (chunkData.name === 'widgets') return 'css/widgets.css';
return 'css/[name]-[contenthash:8].css';
},
})
);
Most helpful comment
I haven't tested this too much but you should be able to achieve this using a simple webpack config.