-
-
Notifications
You must be signed in to change notification settings - Fork 26.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for public/ folder #703
Conversation
One thing I'm still not sure about is whether |
I would rather have App.js or index.js at the top level because this is the one we want people to change. The fact that index.html is the first time to see when you have a new project is weird imo. |
We'll look at file structure again after adding proper support for absolute imports. For now merging to avoid conflicts in other PRs as this is strictly better than what we have now. |
Looks reasonable to me given the complex weave of constraints and needs.
I recommend 'both', meaning:
Upsides are it's backward compatible and makes more reasonable sense than having Downside is additional complexity which I'm not in the position to properly measure. |
Putting So, |
Good catch regarding second index.html. Yea, I like it being in public better as well. |
One concern is that you have both One possible solution to this would be to add a special |
Yep, supporting bundling for something like service worker is a separate feature that I'm happy to discuss in another issue. Indeed I think a separate conventional entry point be the best way to go. Also if I'm not mistaken Webpack provides a separate target for workers. |
This is now supported in 0.5.0. Read about using the new See also migration instructions and breaking changes in 0.5.0. |
I’ve been thinking about this for a few weeks and I have a solution for static assets that satisfies me.
It is not exactly what we discussed before so please bear with me and give it five minutes.
Problem
Currently, the only way to use an image or another resource is to
import
it from JavaScript.This works really well for most use cases because Webpack takes care of:
However there are a few problems with this approach.
Let me group them into a few buckets:
[ROOT-NAMES]
Some files (e.g.favicon.ico
ormanifest.json
) must exist at top level. Default approach of putting them intostatic/
and adding a content hash doesn’t work for them and we have to add exceptions. (manifest.json <link hrefs> turn into [object Object] #558, How to add static json file to index.html? #697)[ANY-ATTRIBUTES]
HTML needs to be able to refer to asset paths inside any attributes. For example, some<meta>
tags may want to refer to an image URL in theircontent
, but we can’t be sure which ones. (Meta tag with image url content #618)[DYNAMIC-FILES]
Sometimes you have hundreds of image files that rarely change, and you want to do something dynamic instead of making hundreds of imports. (Can't import image from src #585 (comment))[SKIP-BUNDLER]
Sometimes you really want to load some JS or CSS independently of the bundler, for example, to show a spinner, or to use a script that somehow breaks Webpack. (Link css in index.html, ReferenceError: window not defined #625, version 0.4.1 serves non-HTML files as text/html #573 (comment))This means we need an alternative way of including some assets into the build.
Constraints
[PROD-WORKS]
If it works in development, it must work in production too.[HOMEPAGE]
User may specify a customhomepage
inpackage.json
, and we should respect that.[ROUTING]
User may use client-side routing, and app may be served from an arbitrary subpath.[SECRETS]
It should be obvious to the user which files or folders will end up in the build output.[PIT-OF-SUCCESS]
There should be one relatively obvious way to do it.Prior Solutions
Implicitly Serve Everything in Development
This is how it worked prior to 0.4.0.
It wasn’t intentional, but WebpackDevServer defaults to this behavior.
This means
<img src="/src/logo.svg">
or<link rel="shortcut icon" href="/favicon.ico">
happened to work in development. However once you compile them withnpm run build
, the links would be broken because module system knew nothing about those files.Verdict: solves all problems but violates
[PROD-WORKS]
.Auto-Detect Assets in HTML
This is the current solution that was added as a stop-gap measure in 0.4.0. Any
<link href>
attribute is being parsed, and relative URLs like./favicon.ico
get processed through Webpack.Verdict: does not violate the constraints but also does not solve
[ROOT-NAMES]
unless we keep an extensive whitelist. JSON files make it nearly impossible to keep a whitelist like this because they should be treated differently depending on whether they’re imported from HTML or JS (and Webpack doesn’t support this). Similarly,[ANY-ATTRIBUTES]
,[DYNAMIC-FILES]
, and[SKIP-BUNDLER]
are unsolved.Introduce a Static Folder and Serve It
This is the approach described in #226. If an additional
/static
folder exists, it is served under/static
and is merged with/build/static
on build.Verdict: it does not solve
[ROOT-NAMES]
unless we mergestatic/*
directly intobuild/*
output. However, in that case, for something to be served from/static/
, you’d have to createstatic/static
which is confusing and violates[PIT-OF-SUCCESS]
. It also violates[PIT-OF-SUCCESS]
because to refer to something, you’d have to use/static/*
paths in your HTML, but to many people, this would imply that/src/*
or/img/*
would work the same way. Most importantly, it violates[HOMEPAGE]
because there is no way for us to fix/static/
path to have the right absolute prefix without parsing HTML and applying some brittle heuristics. It would also be confusing that/static/
paths get “auto-fixed” in HTML while other paths are kept intact. Finally, if we proposed that user types relativestatic/*
in HTML instead, it would violate[ROUTING]
.Proposed Solution
There is a new top-level folder called
public
. We moveindex.html
andfavicon.ico
there.We introduce a new concept called “public URL”. It roughly corresponds to “public path” in Webpack.
It is already configurable via
homepage
field inpackage.json
, but now we also expose it to the user.In HTML:
In JavaScript:
Only files inside
public
folder are accessible by public URL. You can’t refer to things fromnode_modules
orsrc
. Thepublic
folder contents gets merged with thebuild
output.Let’s see how this proposal addresses each of the problems and constraints.
Addressed Problems
With
public
folder, you have full control over how to call your files.With
%PUBLIC_URL%
, you have full control over attributes.We expose
process.env.PUBLIC_URL
so you can do that now.Again, since we don’t process files in
public
folder with webpack, this will work.Addressed Constraints
The
public
folder gets merged with the build output, so references both from HTML and JS will keep working in production.Both
%PUBLIC_URL%
andprocess.env.PUBLIC_URL
takehomepage
into account, as they directly correspond topublicPath
used by Webpack.Both
%PUBLIC_URL%
andprocess.env.PUBLIC_URL
provide safety against that, as they are absolute and know abouthomepage
.The mental model is simple: only
public
files are merged with build output.You can’t accidentally refer to a file in
src
ornode_modules
because it will not work. We show two preferred methods out of the box:import
ing images inApp.js
, and using%PUBLIC_URL%
inindex.html
. Usingprocess.env.PUBLIC_URL
is an escape hatch so we will only use mention in documentation for people who need it.Overall I feel like it’s a solid, explicit solution, and I intend to release it as part of 0.5.0.