Skip to content
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

Wrong relative links in sub directory when a relative public url is specified #2786

Open
codingphil opened this issue Mar 13, 2019 · 13 comments

Comments

@codingphil
Copy link

codingphil commented Mar 13, 2019

🐛 bug report

This bug is related to the issue #2774
and also to this pull request: #2740

If you specify the parameter --public-url ./ when calling the parcel cli (like it is described in the doc for the cli) the relative links (e.g. hrefs) are relative to the root directory and not relative to the sub directory in which the bundle/html file is located.

repro-html-in-subdir.zip

src
├── subdir1
│   ├── subdirpage.html
│   ├── subdirpage.js
│   └── subdirpage2.html
└── index.html

🎛 Configuration (.babelrc, package.json, cli command)

See attached project above.

{
  "name": "repro-html-in-subdir",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "clean": "rm -rf .cache node_modules dist",
    "start": "parcel serve src/index.html --global Global",
    "build": "parcel build src/index.html --detailed-report --log-level 4 --no-source-maps --no-minify --public-url ./"
  },
  "devDependencies": {
    "parcel-bundler": "1.x"
  }
}

🤔 Expected Behavior

After you call yarn build in the output directory dist there is the file subdir1/subdirpage.html.
The content of the file should be:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Sub Directory Page</title>
</head>
<body>
    <h1>Sub Directory Page</h1>

    <a href="subdirpage2.html">subdirpage2.html</a>

    <script src="../subdirpage.7501a095.js"></script>
</body>
</html>

The bundle resulting from the file subdir1/subdirpage.js is subdirpage.7501a095.js which currently is located in the root dist folder.
The file subdirpage2.html is located in the same folder as subdirpage.html the the relative link should reflect this fact.

😯 Current Behavior

The content of the bundled file subdir1/subdirpage.html is the following:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Sub Directory Page</title>
</head>
<body>
    <h1>Sub Directory Page</h1>

    <a href="subdir1/subdirpage2.html">subdirpage2.html</a>

    <script src="subdirpage.7501a095.js"></script>
</body>
</html>

As you see the URL of the href to the file subdirpage2.html which is in the same folder as subdirpage.html is wrong (does not point to the current folder).
Also the link to the bundled JavaScript file subdirpage.7501a095.js which is located in the root dist folder does not point to the parent folder.

💁 Possible Solution

In my opinion in the method Asset.replaceBundleNames() (/packages/core/parcel-bundler/src/Asset.js) the relative URL should be calculated based on the directory of the parent bundle path (like the path which is calculated here:
https://github.com/parcel-bundler/parcel/blob/parcel-bundler%401.12.1/packages/core/parcel-bundler/src/Bundle.js#L162).
The parent bundle in the example above is subdir1/subdirpage.html.
This should be only be done if the replaced bundle path is relative and the value of the publicURL option is a relative url (like ./).

replaceBundleNames(bundleNameMap) {
...
...
        for (let [name, map] of bundleNameMap) {
          newValue = newValue
            .split(name)
            .join(this.makeBundlePathRelativeToParentBundle(map));
        }
...
...
}

  makeBundlePathRelativeToParentBundle(bundlePath) {
    if (path.isAbsolute(bundlePath)) {
      return bundlePath;
    }
    // if this.options.publicURL is NOT relative also return bundlePath
    
    const parentBundleRelativePath = // get relative path of this.parentBundle (something like this.parentBundle.getHashedBundleName()??)
    const parentBundleRelativeDir =
      path.dirname(parentBundleRelativePath) || '.';
    const relativeBundlePath = path.relative(
      parentBundleRelativeDir,
      bundlePath
    );
    return relativeBundlePath;
  }

🔦 Context

We as a dev team want to structure our web application by putting HTML files and JavaScript files of parts of the site into sub directories. This is currently only possible for JavaScript files but not for HTML file because of this bug.
The example project attached to this issue is an abstract representation of our web application.

💻 Code Sample

repro-html-in-subdir.zip

🌍 Your Environment

Software Version(s)
Parcel 1.12.1
Node v10.13.0
npm/Yarn Yarn 1.13.0
Operating System Ubuntu 18.10
@codingphil codingphil changed the title wrong relative links in sub directory when a relative public url is specified Wrong relative links in sub directory when a relative public url is specified Mar 13, 2019
codingphil pushed a commit to frux-technologies/parcel that referenced this issue Mar 14, 2019
@tobiaskraus
Copy link

Exactly the same problem, I just ran into. Happy to see soon some fixes on this matter.

tobiaskraus added a commit to tobiaskraus/svg-gen that referenced this issue May 11, 2019
* replace d3-voronoi with delaunator
* tsc commpiler might complain cause of @types/delaunator
  @types/delaunator version 3.0 is coming soon and will fix it
* examples/src folder cannot have subfolder as relative paths are buggy
  in parcel-bundler
  (parcel-bundler/parcel#2786)
* add examples/README.md
@benfrain
Copy link

Same issue. @codingphil how are you working around this currently? Just putting everything in the root?

@codingphil
Copy link
Author

codingphil commented May 24, 2019

Same issue. @codingphil how are you working around this currently? Just putting everything in the root?

I'm currently using a self built version of parcel with my pull request included ;-)

@thewilkybarkid
Copy link
Contributor

There's a merged PR, but I'm still seeing this behaviour with Parcel 2.

@mischnic
Copy link
Member

@thewilkybarkid Can provide a code sample with Parcel 2?

@thewilkybarkid
Copy link
Contributor

Using Parcel 2 on the original code sample still breaks:

parcel-public-url-bug.zip

@mischnic
Copy link
Member

@thewilkybarkid Why are you using --public-url=./ ? It works without that

@Aaronius
Copy link

@codingphil Is your self-built version of parcel public somewhere? I noticed you said "with my pull request included", but I didn't really understand that part. We have this same problem and are looking for a fix.

@codingphil
Copy link
Author

codingphil commented Feb 17, 2021

@codingphil Is your self-built version of parcel public somewhere? I noticed you said "with my pull request included", but I didn't really understand that part. We have this same problem and are looking for a fix.

@Aaronius No. Sorry.

I just checked the source with my pull request out locally, changed the version number so that it didn't conflict with the public version, built it and published it to the company internal npm repo. Then I referenced this exact version from the project where I used parcel.

This pull request does not work for parcel v2, of course.
I'm not working at the company any more at which I used parcel and created the pull request.
Therefore I'm not very motivated to try to investigate and fix the issue in v2. Sorry again.

@Aaronius
Copy link

Oh, I think you're talking about this pull request. Thanks @codingphil. So it looks like that PR was never released (at least under 1.x). This gives me something to work with. Thanks.

@codingphil
Copy link
Author

Oh, I think you're talking about this pull request. Thanks @codingphil. So it looks like that PR was never released (at least under 1.x). This gives me something to work with. Thanks.

Yes. I was not able to get the tests green (they were kind of flaky - unrelated tests failed).

@Aaronius
Copy link

Aaronius commented Feb 18, 2021

Yeah, that fixed our problem. It fixed another problem we were having as well, which is that when we specified a publicUrl and our source HTML file had a script tag referencing a JSX file, the post-processed HTML file left the .jsx file extension in the script tag's src attribute value, rather than changing it to .js.

Thank you for your work on this!

@shasherazi
Copy link

Is there any development on this? I'm also facing this bug.

Here is my dist directory.

dist
├── index.9fdc10c0.css
├── index.9fdc10c0.css.map
├── index.b1d22321.js
├── index.b1d22321.js.map
├── index.html
└── pages
    ├── blogs
    │   └── mistakes.html
    ├── blogs.a8089d62.css
    ├── blogs.a8089d62.css.map
    └── blogs.html

In dist/index.html, my CSS is linked correctly as

    <link rel="stylesheet" href="index.9fdc10c0.css" />

But in my dist/pages/blogs.html, the path is wrong, as shown below.

    <link rel="stylesheet" href="pages/blogs.a8089d62.css" />

Which is wrong. Instead of pages/blogs.a8089d62.css, it should have been ./blogs.a8089d62.css.
Same with every other nested HTML page. Links are just out of place.

Here is my package.json

{
  "name": "portfolio",
  "version": "1.0.0",
  "author": "shasherazi",
  "license": "WTFPL",
  "source": "./src/index.html",
  "scripts": {
    "start": "parcel",
    "dev": "parcel serve --open",
    "prebuild": "rm -rf dist",
    "build": "parcel build './**/*.html' --public-url ./",
    "deploy": "npm run build && echo shasherazi.me > ./dist/CNAME && gh-pages -d dist"
  },
  "devDependencies": {
    "eslint": "^7.32.0 || ^8.2.0",
    "eslint-config-airbnb-base": "^15.0.0",
    "eslint-plugin-import": "^2.25.2",
    "gh-pages": "^5.0.0",
    "hint": "^7.1.3",
    "parcel": "^2.8.3",
    "typescript": "^4.9.5"
  },
  "repository": "git@github.com:shasherazi/portfolio.git"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants