facebook/create-react-app

"Vendor" folder

gaearon opened this issue · 35 comments

Let’s wait until somebody asks before implementing but.. I think a vendor folder that just gets copied into the output could be a useful escape hatch. For example, if you have a global script that isn’t UMD-friendly, you want to have some way of importing it. With a vendor folder, you could just put it there, reference it from index.html, and read from window in your bundle.

This would also be useful for files referenced solely in index.html, like manifest.json, or apple-touchìcon.png, and scripts like web workers and service workers.

This would also be useful for files referenced solely in index.html, like manifest.json, or apple-touchìcon.png, and scripts like web workers and service workers.

Yep.

Hi there, I just bumped into this issue.

I am trying to implement this using copy-webpack-plugin but I can't figure out how to test my branch.
Are there are notes on doing this?

Ciaran

Does this help? https://github.com/facebookincubator/create-react-app#contributing

Also, we’d need to solve #21 first because this change will also have implications for it.

vendor doesn't seem like the right name here. Seems more like it should be something like "assets". i.e. this is about serving files that don't need building, not necessarily files that have been vendored in.

Yeah, I agree it’s a bad name. (I don’t like assets because people will immediately think it’s the place to put their CSS and images in.. which it is not.)

Maybe we should just use html-loader and make it that <link href> is automatically rewritten and those files are also processed by webpack. I feel like this could solve the majority of cases (e.g. touch icons or vendor CSS sheets), and even use webpack’s features like content hashes.

I've been using static for some time now, with good understanding from the rest of the team(s) about it containing purely copied, unprocessed assets. It has been a useful crutch for when a resource path is dynamically generated and/or webpack processing is not required/wanted.

I like the name static - it's the folder name Django encourages, and it is also a pretty accurate description of what goes there - the files that are not dynamically generated by some process, but are just a static copy of what's in your filesystem. As opposed to assets which implies that it has to be some sort of image or media asset.

static looks like a better name than vendor or assets.

I love static, working on a PR now! 🚢

I actually agree with not having a special directory at all. All the
compiled files will be static assets anyway. I think just having babel load
resources referenced by html files would be better. This also gives you
more freedom in your folder structure.

On Tue, Jul 26, 2016 at 7:57 PM Héliton Nordt notifications@github.com
wrote:

static looks like a better name than vendor or assets.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#28 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAtA1c3w9cK6QqOkQrYcv_Y2gq9yzE7Jks5qZkp4gaJpZM4JQQtC
.

taion commented

Also worth noting that in general static assets should not go in this directory – they should just be imported and dealt with by webpack loaders. I.e. this is the wrong way to pull in e.g. Bootstrap CSS.

Bringing this up for discussion as noted in the Readme re:images

I think this style of loading images works for most cases

import logo from './logo.png';
<img src={logo} alt="Logo" />;

I worked on a project pre create-react-app where I had to work with roughly 5000 images.

The images were in directories roughly in this style img/large/building_type/texture_type/colour

Given x # of buildings and x # of colours the path to the images had to be dynamic

The filenames were all provided so this looks more complicated than it was but ... I ended up with this

const path = `${assetPath}/img/large/${buildingPath}`
const clad = `${path}cladding/amB${toTitleCase(building)}C_DR_${cladObj.file}.png`

For Local dev assetPath was '' for Prod it was roughly '/client/myapp/'

Bit crazy but it's a real world use case (perhaps a one off and not to worry about).

Creating import statements in such a case wouldn't make any sense.


In this case for prod I could easily add the domain and get it to work but locally I don't think that would work with Webpack dev server.


Wasn't sure if I should even bring this up as it's not a typical setup but figured I should at least mention such a case.

Something like a Photo Gallery might be a more typical use case.

@timarney I sort of feel that for this use case you’re better off serving them from a local static server on a different port, and deploying them to a CDN in production.

@gaearon ya I think your right. It's really only a problem for local dev and it's fairly trivial to work around as you suggest.

i'm in the same kind of issue than @timarney , we have like sentry dns ... or api url or other config key that depend on the server / env. It would be cool to be able to "load" a and external js/json/something file to "configure" our app at run time.

You have access to environment variables. This is documented in the usage guide in this repo. Does that help?

@gaearon yes I saw it... but it seems to help only for the dev version.. not for the builder one... Or I'm missing something?... I don't want those config variables into my compiled bundle... Because it change with every deployment

Do you mean that you want to deploy the same build output to different servers, and making a separate build for each environment separately would be a pain?

Hum... Didn't think about that... might be possible but not really practical... And the tooling to make the multiple builds for dev/prod has to be made...
But wat if i want to distribute as compiled bundle but still with configurable parts...

PS: I totally understand and share your quest to keep it simple stupid and avoid any config. Just sharing my current workflow/issues

You could post-process HTML for this like described here.

<head>
  <script>
    // $CONFIG
  </script>

You can replace // $CONFIG with something like window.CONFIG = { something: 42 } depending on environment before deployment, and you can have a fallback in your code if window.CONFIG doesn’t exist.

I’m closing because I’m coming to the conclusion that this is either unnecessary or out of scope of CRA. Currently we give a strong guarantee that if a file changes, browser cache will be busted. We also give a single way to include images and other assets. I would prefer to keep it this way, and address other use cases on a case by case basis (e.g. #558).

I drafted a proposal to solve this in #703. Unless we find some fatal flaws, it should come out in 0.5.0. Let me know what you think!

This is now supported in 0.5.0.

Read about using the new public folder.

See also migration instructions and breaking changes in 0.5.0.

Hi gaearon, I'm still looking for what you asked in the op which was the ability to bring a pre-minified javascript file into the bundle without it passing through webpack's minifier. Would it be possible to put this back on the to do agenda?

Edit: I do believe in the need for create-react-app as well as the need for alignment of general react ecosystem

Possible workarounds are to delay the firing of "ReactDOM.render of < App / > on #root until vendor files have loaded. This would mean include the vendor files in public, and linking to them in public/index.html and have them fire events off the window after each of them have loaded

Hi gaearon, I'm still looking for what you asked in the op which was the ability to bring a pre-minified javascript file into the bundle without it passing through webpack's minifier. Would it be possible to put this back on the to do agenda?

Not into the bundle, but it's possible to put it into the public folder and load as a separate <script> tag. Does that help?

Thats what I meant in the post just before your reply. It does mean figuring out a way to prevent the bundle from running before the other scripts have loaded

Can also bring the script in and let it pass thru the web pack minification again and hope it is fine (it should be theoretically)

The main bundle will always run last as far as I know. The bundle script is appended to the end of the document body.

The calls are made asynchronously so bundle can start running before one of the earlier scripts has returned its called

JS scripts wait for each other to execute. If your earlier script needs to do something async then you should export a global that lets the other script to wait:

// myscript.js
window.waitForThingsToHappen = function() {
  return fetch(/* ... */).then(/* whatever */);
}

// index.js
window.waitForThingsToHappen().then(() => {
  ReactDOM.render(<App />, root);
});

Got it. Thanks @gaearon