facebook / create-react-app

Set up a modern web app by running one command.
https://create-react-app.dev
MIT License
102.52k stars 26.79k forks source link

Option not to include hash to file names #3855

Open FixRM opened 6 years ago

FixRM commented 6 years ago

First of all thanks for this tool! It was really helpful for me to get started. I read all available how-to's and materials and really understand the purpose of this tool BUT... If this app is agnostic of the backend, and just produces static HTML/JS/CSS bundles there should be an option to leave filenames as is, as some ECM/CMS and other host systems has their own caching/versioning realization. Having different file names after each build mean need for manually deal with file published previously.

gaearon commented 6 years ago

Having different file names after each build mean need for manually deal with file published previously.

Can you expand on how this creates the difficulty? What is the workflow like?

FixRM commented 6 years ago

Hi! The workflow is following: CMS has it's own internal project-solution tracking system. Each web resource (html/css/js etc.) is saved in database and filename is used as alternative key for tracking project dependencies, or doing updates. If file name is changed the are two options for me: update each resource manually after each change or publish them as new resources. If I choose second option I'll have mess of unused resources in my project but they still be tracked as dependencies and will be moved to production environment after project import / export process.

heyimalex commented 6 years ago

If you're looking for a solution right now, there are definitely ugly ways to automate this using asset-manifest.json, which is a sort of mapping from the original names to the hashed names.

FixRM commented 6 years ago

Thanks. As for now I choose eject and modify webpack config in 3 or 5 places. That's why I'm proposing a centralized option suitable for config or doing fork

andriijas commented 6 years ago

Feels like a very specific use case. Most users benefit from cache busting naming convention. Being able to set far future expire headers on static assets speeds loading up of the site for revisits. It sounds like you can read the asset-manifest and feed your DB with it.

FixRM commented 6 years ago

Unfortunately it's not specific in MS world. In most cases we have to include static files to Visual Studio projects to be able to publish them. There is specific but it's normal case here.

gaearon commented 6 years ago

If you're looking for a solution right now, there are definitely ugly ways to automate this using asset-manifest.json, which is a sort of mapping from the original names to the hashed names.

This does sound like the right way to me. And you could right an automated script that reads it, does something, and even share that script between projects.

FixRM commented 6 years ago

Sorry but I can't understand how can it help me if build command will generate index.html with references to files with hashes?

heyimalex commented 6 years ago

Hm, I was thinking more that you could feed your cms with it. Is there really no way to specify renamed resources, or to remove old resources from the project? Since the main issue is the "mess of unused resources".

If that's not an option, then ejecting is probably the best bet right now. You could do find/replace and rename using the asset manifest, but thinking about it now it might break source maps.

deanolium commented 6 years ago

Whilst this is something which is rare, there are some use cases for this. For my company, we develop web apps to be served on a survey platform. This platform allows us to upload the .js and .css files onto their site, but the relevant contents of the index.html has to be copy/pasted into a question form on this platform (ie, a HTML block). Currently hashing means every time we do a change to the code, we not only have to upload the bundles, but then manually go to the html block, copy/paste the new name of the bundle and resave that page. Being a manual process, this is error-prone as well as plain slow.

Being able to turn hashing off would save a lot of pain and potential errors for this use-case. Obviously we can just eject, but that is meant to be a last resort.

WolfieZero commented 6 years ago

I'm currently in this situation where the hashing in filenames causes issues. Whilst ejecting is a solution, it seems like a broken solution.

FixRM commented 6 years ago

@WolfieZero, I did a fork and made some changes in react scripts package to get static names after build. It may be not best way but it is still much better then doing eject. Please refer to this manual: https://auth0.com/blog/how-to-configure-create-react-app/. As far as I understand it is supported approach

WolfieZero commented 6 years ago

@FixRM Awesome, will take a look at. Thanks!

FixRM commented 6 years ago

@WolfieZero You can try mine but it uses TypeScript: https://github.com/FixRM/create-react-app-typescript-static

Havret commented 6 years ago

Why don't you add query hashes instead of hashing file names?

If you generate your HTML in that way everyone should be satisfied.

ianschmitz commented 6 years ago

@Havret the downside to query strings is intermediate proxies (such as CDNs) will often ignore the query string by default.

santimendoza commented 6 years ago

I am needing this to (bundles without hashes). I dont think it to be so hard to implement. And should be like and option (by default include the hashes)

NateAGeek commented 6 years ago

Something that I was able to do with React Rewired (https://github.com/timarney/react-app-rewired). I will say that if you are really overriding a lot in the future it might be worth ejecting.

// config-overrides.js
module.exports = {
  webpack: function(config, env) {
    if (env === "production") {
      //JS Overrides
      config.output.filename = 'static/js/[name].js';
      config.output.chunkFilename = 'static/js/[name].chunk.js';

      //CSS Overrides
      config.plugins[4].filename = 'static/css/[name].css';

      //Media and Assets Overrides
      config.module.rules[1].oneOf[0].options.name = 'static/media/[name].[ext]';
      config.module.rules[1].oneOf[3].options.name = 'static/media/[name].[ext]';
     /**
       * If the media/assets public path differs on the server
       * 
       * config.module.rules[1].oneOf[0].options.name = 'static/media/[name].[ext]';
       * config.module.rules[1].oneOf[0].options.publicPath = '/public/assets/';
       * config.module.rules[1].oneOf[3].options.name = 'static/media/[name].[ext]';
       * config.module.rules[1].oneOf[3].options.publicPath = '/public/assets/';
       */

    }

    return config;
  }
};

This should take care of the hashes, mapping, and media/asset. Sadly with the way plugins are implemented in an array, I have to use fixed indexes. Also, if you do end up adding more plugins it could mess with those fixed indexes.

BrunoDesthuilliers commented 5 years ago

We serve our react app from Django staticfiles, and we use Django's builtin CachedStaticfFilesStorage, which itself takes care of hashing all static assets etc, so we end up with a doubly hashed bundle :-/ This is really a PITA and I really don't understand why there's no simple option to deactivate hashing in create-react-app. Really, why force peoples to go through all sorts of hoops just to make things work for their own use case ?

dlbnco commented 5 years ago

I'm also having issues with this, here is the scenario:

The app is hosted on Netlify. Since it's a SPA, redirect rules are set to redirect any route to index.html.

First access to app caches the current bundle name. If a new deployment/build is done, a new bundle name is generated.

In a second access, the browser still requests old bundle name generated on first build. Server doesn't find requested js file, so redirect rules apply and index.html is served as a js file.

Result is a blank page and the following error on console since it tries to read js but server delivers a HTML file:

Unexpected token <
route2Dev commented 5 years ago

Other SPA framework (Angular / Vue) CLIs support this. Ejecting feels like taking a sledge hammer to crush an ant.

Having non-hased output files is helpful if you are using something other than the generated index.html to host the SPA. An example would be hosting a new React SPA in a razor (.cshtml) view in an existing ASP.NET MVC project. I want / need the script src locations to be known at development time as this file is under source control.

Otherwise, I could update my build server to perform magic to insert the for my production builds. But then what I deploy is not reflected in source control.

Without the hashed files, cache busting would be up to the developer. But that's the trade-off we would be willing to make for predictability.

djyadav commented 5 years ago

@dlbnco We are facing the exactly same issue. So, The application fails if we deploy it while a user is online.

The app is hosted on Netlify. Since it's a SPA, redirect rules are set to redirect any route to index.html.

First access to app caches the current bundle name. If a new deployment/build is done, a new bundle name is generated.

In a second access, the browser still requests old bundle name generated on first build. Server doesn't find requested js file, so redirect rules apply and index.html is served as a js file.

Result is a blank page and the following error on console since it tries to read js but server delivers a HTML file.

Kyr commented 5 years ago

May I suggest that #7172 may resolve such problem without ejecting?

Stv1 commented 5 years ago

hello could someone correct this? i have the same problem.

BrunoDesthuilliers commented 5 years ago

Ok so we now have at least half a dozen users that explicitely claimed they had a need for this feature (which means quite a few others also do who have not posted here yet), and at least a couple more-or-less supported "solutions" (either forks or workaround like react-app-rewired). Not mentionning those who choosed to "eject" but would rather not have if they add a better (builtin) solution.

May I kindly suggest that it may not be such a "very specific use case" and that the fact that "Most users benefit from cache busting naming convention" is actually unrelated since the point is not to remove this feature but only to add an option to deactivate it ? (without having to deal with the inconveniences of the existing "solutions", that is).

FWIW I'm actually a bit suprised that Kyr's PR (cf #7172) was rejected on the premise that "this has little value for most users" - it obviously has for quite a few of us, and AFAICT it wouldn't change anything for those "most" users who don't need it.

Now I'm no react/webpack expert in anyway so there might be other technical issues (with Kyr's solution or anything similar) that I'm not aware of, but then why not just expose those issues (so someone - possibly me or someone from my team FWIW) has a chance to come with a working fix that could be accepted) instead of assuming what CRA users really need ?

My 2 cents...

andriijas commented 5 years ago

@BrunoDesthuilliers And where are everyone who are happy about the way it currently works and how many are those? :) Just to balance things up... I dont like guessing but most people probably just dont question why the bundled file names are named the way they are.

I think deactivating it has significant down sides and can lead to unwanted side effects compared to building something that reads the manifest file.

BrunoDesthuilliers commented 5 years ago

@andriijas I'm afraid I wasn't clear enough: I'm not talking about removing hashing, but about having an option to disable it (via a command line flag, envvar or config, whatever). IOW: keeping the exact current behaviour as default, but having an easy (and controlable) way to change it when necessary.

Oh and yes also: except for this point (and even despite this point) I am a happy CRA users, thank you guys ;-)

FixRM commented 5 years ago

As far as I see, some people also have problems with v3 chunk/hashing schema. The option to disable this can be a rescue for them as well

BrunoDesthuilliers commented 4 years ago

Oh and yes, wrt/

most people probably just dont question why the bundled file names are named the way they are.

Well, they should, really - or, more exactly, they should not, because they should already know why those hashes are there. But it's not because some users don't understand why this feature is there or aren't even aware it exists that there's no perfectly legitimate use cases for allowing other users to disable it.

danielimmke commented 4 years ago

The other Issue that was about this was closed a while ago but I wanted to add my own updated package.json that works with dropping the hashes out of a chunked file for people Googling:

"build": "react-scripts build && npm run rename-build-files && npm run replace-build-files-text",
"rename-build-files": "renamer -f '/\\.[^\\\\.]+\\.chunk\\./gmi\\' -r . 'build/**'",
"replace-build-files-text" : "replace-in-file '\/\\.[^\\\\.]+\\.chunk\\.\/g' '.' 'build\/**' --isRegex --verbose"

Uses the renamer package to actually change the filenames and replace-in-file to change the references.

The raw, unaltered commands (you have to escape them to put them in package.json) are: renamer -f '/\.[^\\.]+\.chunk\./gmi\' -r . 'build/**' replace-in-file '/\.[^\\.]+\.chunk\./g' '.' 'build/**' --isRegex --verbose

If you wanted to add query string cache busting you could probably write another line using the replace-in-file to do it.

RXminuS commented 4 years ago

Would love to see the ability to witch to query based hashes. That way logrocket would finally work correctly with our Netlify deploy https://docs.logrocket.com/docs/troubleshooting-sessions#styles-are-not-appearing-in-recordings

rsomepalli commented 4 years ago

If you're looking for a solution right now, there are definitely ugly ways to automate this using asset-manifest.json, which is a sort of mapping from the original names to the hashed names.

This does sound like the right way to me. And you could right an automated script that reads it, does something, and even share that script between projects.

lot of requests for this over the years, is it a technical issue that is difficult to fix or a disagreement on that it not needed

TuureKaunisto commented 2 years ago

We'd also appreciate the option to not add hashes to file names and use query strings or other methods to bust the cache instead so that when someone has an expired html file, they still get the js files instead of a blank page.

The janky workaround we ended up going with to solve this is serving the new bundle.js file even if the hash doesn't match.

toabi commented 1 year ago

Here's a minimal working configuration for react-app-rewired which works for us:

module.exports = function override(config, env) {
    if (env !== "production") {
        return config;
    }

    // Get rid of hash for js files
    config.output.filename = "static/js/[name].js"
    config.output.chunkFilename = "static/js/[name].chunk.js"

    // Get rid of hash for media files
    config.output.assetModuleFilename = 'static/media/[name][ext]'

    // Get rid of hash for css files
    const miniCssExtractPlugin = config.plugins.find(element => element.constructor.name === "MiniCssExtractPlugin");
    miniCssExtractPlugin.options.filename = "static/css/[name].css"
    miniCssExtractPlugin.options.chunkFilename = "static/css/[name].css"

    return config;
};