Parcel: --public-url only works when set to / - No other options lead to a served JS file

Created on 19 Feb 2018  路  34Comments  路  Source: parcel-bundler/parcel

Original file: /projectRoot/app/app.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>MyApp</title>
  <link rel='stylesheet' src='app.global.css' />
</head> 
  <body tabindex="-1" disabled="disabled" focusable="false" aria-label="">
    <div id="root"></div>
    <script src="index.js"></script>
  </body>
</html>

Output file: /projectRoot/dist/app.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>MyApp</title>
  <link rel="stylesheet" src="app.global.css">
</head> 
  <body tabindex="-1" disabled="disabled" focusable="false" aria-label="">
    <div id="root"></div>
    <script src="/dist/c91b3d0cbbf15cbf3cda41e594a40ff1.js"></script>
  </body>
</html>

The Javascript src is always pointing to the dist folder a level deeper than it should. I cannot find any way to correct this. Any thoughts? Thanks very much.

馃實 Your Environment

| Software | Version(s) |
| ---------------- | ---------- |
| Parcel | 1.6.1
| Node | 8.9.1
| npm/Yarn | 1.3.2 (yarn)
| Operating System | Windows 7 x64

Bug

Most helpful comment

Tip: When you change --public-url/publicUrl, delete the .cache folder. I was getting incorrect results when I changed that setting but kept the cache.

All 34 comments

use --public-url ./ ?

That would appear to work on the surface, but my Javascript file simply contains my app.html contents when I load it in the browser. On the filesystem though, the Javascript file seems to contain correctly bundled Javascript.

Without --public-url ./ the server serves the correct bundle, but the app.html does not point to it. Any thoughts?

It should build the exact same bundle with or without the --public-url flag.
Could u possibly provide a test repo?

I would figure as much, and it does build the same bundle, but it isn't serving it. It serves my app.html under the name of the Javascript file.

The dev server seems to point any unresolved address to my app.html, so I assume this means that the file is not being found where one would expect.

I've tried the command configured in a variety of ways in the Windows cmd prompt and in Babun, but the same results no matter what. The JS file is served properly and the app.html doesn't point to it, or the app.html points to the proper place, but the JS file is not served properly.

In this second case I can't find anywhere the JS file is being served from at any directory level.

I am running without caching, with the flag --target=electron

I've now tried various settings for --public-url and tried combining it with various --out-dir settings as well, but in no case where --public-url is used do I have a javascript file served. I've looked everywhere. I also tried installing Parcel as a local devDependency. No luck.

--public-url only works when set to /

In my hour of investigating, no other setting yielded a javascript file being served at any location I can find.

This resolves my particular issue, but the --public-url flag appears to have problems.

I'm very new to parcel and also seeing this issue. I whittled it down to a test repo.

(1) yarn (or npm install)
(2) firefox dist/index.html <-- should see the green message
(3) yarn start <-- load in browser, no green message

parcel-issue-857.tar.gz

The issue seems to be that parcel's builtin web server handles what should be a 404 Not Found by returning the index.html file, which results in a JavaScript syntax error when the HTML is not valid JavaScript. Additionally, once we understand that said response should be 404 Not Found, we still don't know how to make parcel serve the correct file.

Running without --public-url is still broken because parcel issues paths with the /dist/ directory, which is there to contain the output, not to be part of the final artifact.

The reason it returns index.html on 404 is for SPAs which do client side routing. In that case, we return the main file and let the client side javascript render the right page.

@devongovett What do you think of an option to disable that behavior on 404s? It can make debugging more difficult.

I think I ave the same issue with --public-url and SPA combination. For any file that's not on FS and not API call, I return index.html and client side routing figures out what to load. This works fine for paths that are not deeper than one level, e.g.

  • http://app.com/ or http://app.com/path1 - loads index.html, JS/CSS are taken from my <static> dir correctly, e.g. http://app.com/<id>.css

  • http://app.com/path1/2 - loads index.html, JS/CSS are taken from <static>/path1 dir, e.g. http://app.com/path1/<id>.css of course that doesn't work and it serves index.html

So, I guess some baseURL detection is broken? paths should always point to <static> dir, irregardless of what URL user tries to access. Is there an option for --public-url that would anchor all requests to '/'?

This is how I make my dev builds:

"start:dev": "NODE_ENV=development concurrently \"nodemon src/server/main.js\" \"parcel watch src/client/index.html -d build/client --public-url ./\""

@coffeeowl I was just getting the same error and was able to solve it by changing --public-url ./ to --public-url /. I also suggest viewing your compiled html file after building and see if your path on your parcel assets are prefixed with a /. If they aren't, that's most likely your issue!

I have this problem too. Files written in ./dist are fine but nothing except the index page gets served.

Example:

test.html:

<h1>test.html</h1>
<script src="test.js"></script>

test.js:

console.log('test.js');

Command, using version 1.10.2:

parcel --public-url '.' test.html

Now http://localhost:1234/ returns the index page as stored in ./dist/test.html. Notice there is no slash in front of the file name, that is the desired outcome of setting --public-url.

<h1>test.html</h1>
<script src="test.e98b79dd.js"></script>

The file ./dist/test.e98b79dd.js looks fine but http://localhost:1234/test.e98b79dd.js _does not_ serve the file.

I had the same problem too after building this demo:
https://github.com/proYang/vue-parcel-demo

Same here, it serves index.html at all paths.
Something is off..., parcel not really usable for me at the moment, cannot integrate it in the project.

Same here, it serves index.html at all paths.
Something is off..., parcel not really usable for me at the moment, cannot integrate it in the project.

Confirm, still same.. Most worst for me is i am not able to use any XHR/ajax request. Still getting index.html page.. :-(

same problem,
so i installed nginx and use parcel watch index.html --public-url "./"

same issue here also.

same issue here, which can be solved using --public-url "./",

BUT I'm using the BundlerAPI, and when I set publicUrl: './', it does not work. If i set publicUrl:'/', it works, but it is absolute path, so if I host it on a web-server in a sub-folder, it does not work. I need a relative path, and I can't find the solution to that.

`const Bundler = require('parcel-bundler');
const args = require('minimist')(process.argv.slice(2));
const game = args.g;

const entry = 'src/' + game + '/*.html';
const options = {
outDir: 'dist/' + game,
publicUrl: './',
}

const bundler = new Bundler(entry, options);
const bundle = bundler.serve();
`

https://github.com/parcel-bundler/parcel/blob/7ad25fd0958cb39c8595a0d667e9bc0f4c0250f4/packages/core/parcel-bundler/src/Server.js#L58

This line checks that the pathname ("/foo/bar.baz" in "http://www.example.com/foo/bar.baz") starts with verbatim whatever is in the --public-url parameter. That makes --public-url='/foo' work, and your index.html (served on / as well as any 404 when doing a parcel serve ...) will point to your js bundle at /foo/src.999999.js.

Then, when the browser requests /foo/src.999999.js, parcel's server will check that the pathname "/foo/src.999999.js" starts with "/foo", then sends the correct file. If you put a ./foo, it fails because something about the bundling makes the ./ disappear from the front when making references in the index.html, so the request just comes to 'foo/src.999999.js'.

This causes two problems: First, the urls are all generated into the html relatively. So if index.html lives at /foo/index.html, then it will try to point to src.999999.js at "foo/src.999999.js". The browser interprets the non-absolute URL reference as "/foo/foo/src.99999.js", which is one nested layer too deep. The second problem is that the "./foo" doesnt match /foo, so it just serves the index.html again.

You can get it to work with just "/foo", because it makes the URLs bundled into index.html absolute instead of relative. This does _not_ work with absolute URLs that include anything before the path. For example: parcel serve src/index.html --public-url='http://127.0.0.1:1234'. This is because the public url specified isn't at the beginning of the pathname. The pathname is only ever the part that comes afterwards, so it never matches. This is interesting because the builds work just fine with the absolute url (at least for my basic build testing).

I was able to look into the full-url for --public-url, and I came up with this snipped which seems to be working pretty well:

    function respond() {
      let {pathname} = url.parse(req.url);
      let public_url_path = url.parse(bundler.options.publicURL);
      if (bundler.error) {
        return send500(bundler.error);
      } else {
        req.url = pathname.slice(public_url_path.pathname.length);
        return serve(req, res, sendIndex);
      }
    }

It is basically the same as the previous one, but it has the advantage of being somewhat aware of the possibility of the --public-url being a full url with domains, ports, etc. It just references the pathname property of the public url, because that matches up with the req url path (the server doesn't seem to know anything about its own url, so this makes sense to remove from the public-url as well).

Is there any progress on this? I'm completely new to parcel, and was just following the documentation and ran into this issue. I just want to run the app on a subpath to closely mirror production, and the docs for --public-url lead straight to a hard to debug error with assets never being served up.

I think at a minimum this should probably be called out in the docs for the CLI. I'm more than happy to create a PR if that's the route parcel wants to take 馃槃

bump....will suggestion by @rlittlefield be a viable solution?

I'm facing the same issue, the solution provided by @rlittlefield will be implemented?

same as @luizfilipe.

bumping this !

bump

Does public url not support full url format like http://localhost:8080/ ?
seems not work for me.

Using v1.12.4 and can't get the build HTML to path to anything other than "/file.*"

Suppose in my 'src' folder I have 'index.html' and 'file.js'.

In my index.html, assets are pathed as per the getting started "./file.js". Running to localhost:1234 everything is fine. When I do a build, I can't get the index.html file to path to anything other than "/file.js".

Tried:

parcel build src/index.html --public-html "/"
parcel build src/index.html --public-html "./"
parcel build src/index.html --public-html "."

They all resort in the same "/file.js".

Is the only option currently to roll back a prior version?

OK, just posted this in the slim chance someone else does the same stupid thing. I had copy and pasted my --public-html command from something I had written previously and it must have been a different hyphen character that got copied. The build command was running without any errors but wasn't working.

As soon as I typed the command in 'fresh' everything worked.

Only took me an hour to figure this out!

For the record, I was wanting to have the URL's it outputs be e.g. "file.js" but it was giving me "/file.js" which worked when served up but not from my local filesystem.

To fix this, I had to use --public-url ./ (or --public-url . also seems to work)

/ without the . would still add the "/".

As a workaround for parcel --public-url './' index.html always serving the contents of index.html for every route, I'm running parcel watch for bundling and http-server for serving, both running concurrently. This way, opening http://localhost:8080 (or whichever port you tell http-server to use) serves the right files and parcel's hot module replacement feature still kicks in.

I'm using a package.json scripts entry so that npm run dev runs both commands:

"scripts": {
  "dev": "concurrently 'npm:watch' 'npm:serve'",
  "watch": "parcel watch --public-url './' index.html",
  "serve": "http-server -c-1 dist",
  "build": "parcel build --public-url './' index.html"
}

Note 1: I disabled http-server's cache with -c-1 flag to avoid hot replacement actually receiving an outdated version of the bundles
Note 2: connecting to 127.0.0.1 instead of localhost or your local IP address (probably something like 192.168.0.*, http-server logs tell you which) breaks parcel's hot module replacement

Tip: When you change --public-url/publicUrl, delete the .cache folder. I was getting incorrect results when I changed that setting but kept the cache.

@warpech nailed it for me -- kept trying different values for --public-url and kept getting the same output in dist/index.html for my bundle src. Blowing away .parcel-cache and rebuilding finally changed the path written to src. 馃檹 馃檹 馃檹

Was this page helpful?
0 / 5 - 0 ratings

Related issues

devongovett picture devongovett  路  3Comments

davidnagli picture davidnagli  路  3Comments

dsky1990 picture dsky1990  路  3Comments

jzimmek picture jzimmek  路  3Comments

donaldallen picture donaldallen  路  3Comments