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

Url filter that outputs relative paths (e.g. ../ or ../../) #648

Closed
stingray21 opened this issue Aug 8, 2019 · 17 comments
Closed

Url filter that outputs relative paths (e.g. ../ or ../../) #648

stingray21 opened this issue Aug 8, 2019 · 17 comments

Comments

@stingray21
Copy link

I am currently working on a 11ty project and really like it. But I have a problem with the links when I deploy the output. I'd like to deploy it to 2 different locations on separate servers. One of the locations is in the root directory, the other one in a sub-folder. It works like a charm for the one that is located in the root directory, but the other doesn't since all the paths are incorrect.

Is it possible to have relative links in the output?

I already tried pathPrefix, but either I don't use it properly or it just doesn't give me the result I am looking for.

.eleventy.js:

module.exports = eleventyConfig => {

    ...

    // Include our static assets
    eleventyConfig.addPassthroughCopy("images")

    return {
        pathPrefix: "/subfolder/",
        templateFormats: ["md", "njk"],
        markdownTemplateEngine: 'njk',
        htmlTemplateEngine: 'njk',
        passthroughFileCopy: true,

        dir: {
            input: 'site',
            output: 'dist',
            includes: 'includes',
            data: 'globals',
        }
    }

}

When I run eleventy --config=eleventy.config.js --serve, an additional folder gets generated with the name _eleventy_redirect, including an index.html file with:

<!doctype html>
  <meta http-equiv="refresh" content="0; url=/subfolder/">
  <title>Browsersync pathPrefix Redirect</title>
  <a href="/subfolder/">Go to /subfolder/</a>

When I run eleventy --config=eleventy.config.js (without the --serve), that folder isn't there.
However, either way all the links are absolute (e.g. Home is href="/"), and the site doesn't work on the server.

Is there a way to have either relative links (e.g. Home is href="./" on the root index.html and href="../" on sub pages) or at least include the subfolder in the urls (e.g. Home is href="./subfolder/")?

@stingray21 stingray21 changed the title Is it possible to have relative paths the output? Is it possible to have relative paths in the output? Aug 8, 2019
@rolandtoth
Copy link

Try href="{{ "/" | url ))", the url filter should take care of this. Imo always add the url filter to links to avoid issues later.

@illycz
Copy link

illycz commented Sep 25, 2019

I'm trying solve same problem, and I'm actually using root variable.
Not perfect but it's working.

  1. I set root = "../" for page in subfolder in front matter.
  2. I link stylesheet stylesheet with this variable <link rel="stylesheet" href="{{ root }}assets/styles/index.css">

Maybe it's good enough for you too :)

@mpalpha
Copy link

mpalpha commented Mar 9, 2020

My solution was to add a relative path filter.

  1. add the filter to .eleventy.js:
  eleventyConfig.addFilter(
    "relative",
    (page, root = "/") =>
      `${require("path").relative(page.filePathStem, root)}/`
  );
  1. Use the filter in "your_layout".njk:
<link rel="stylesheet" href="{{ page | relative }}styles/index.css">

@xuhcc
Copy link

xuhcc commented May 8, 2020

Thanks @mpalpha !

I tinkered a bit with the filter, here's my version of it:

eleventyConfig.addFilter('relativeUrl', (url, page) => {
    if (!url.startsWith('/')) {
        throw new Error('URL is already relative')
    }
    const relativeUrl = path.relative(page.filePathStem, url)
    return path.relative('..', relativeUrl)
})
<link rel="stylesheet" href="{{ '/css/vendor.css' | relativeUrl(page) }}">

@edgarasben
Copy link

edgarasben commented May 20, 2020

I don't know if this is related, but I am running into issues using Typora with 11ty.

My markdown links in Typora are like this: [My page](my-page.md). The top links work fine, but if I am on a subpage, the link slug gets added to that subpage.

For example if I am on example.com/pages/cool-page and I click the link My page, I get to a wrong url example.com/pages/cool-page/my-page.

Is there a way to make it so all links are at example.com/pages?

@mpalpha
Copy link

mpalpha commented May 20, 2020

I have no idea, I don't use Typora. Maybe you could create a markdown function to replace a string with the current relative path.

[My page](@relative@my-page.md)

@pdehaan
Copy link
Contributor

pdehaan commented May 20, 2020

For example if I am on example.com/pages/cool-page and I click the link My page, I get to a wrong url example.com/pages/cool-page/my-page.

Isn't that the correct behavior [since the markdown link is relative and not absolute)? If you want it to be example.com/my-page, style, I think you'd have to do [My page](/my-page.md).

@edgarasben
Copy link

edgarasben commented May 20, 2020

If I change my markdown links, then I am not able to navigate in my markdown editor (Typora). Doing [My page](/my-page.md) brakes the link.

For every page I define a permalink: /posts/my-page/ or /articles/some-article/ . But all markdown files are in the same directory: my-page.md and some-article.md.

@mpalpha
Copy link

mpalpha commented May 20, 2020

I'm not sure then, sorry.

@zachleat zachleat changed the title Is it possible to have relative paths in the output? Url filter that outputs relative paths (e.g. ../ or ../../) Jul 7, 2020
@zachleat
Copy link
Member

zachleat commented Jul 7, 2020

Sounds like this was resolved, thanks folks!

@edgarasben please file your issue separately!

@zachleat zachleat closed this as completed Jul 7, 2020
@edgarasben
Copy link

@zachleat I think I did? #1197

@mpalpha
Copy link

mpalpha commented Jul 23, 2020

I ended up going with a global {{ rootPath }} variable which is relative to the current page.
Inside your data directory create a file called eleventyComputed.js

edited: switched to .reduce and added a filter

module.exports = {
  rootPath: (data) =>
    data.page.url
    .split('/')
    .reduce((a, b) => a+(b && '../'),)
}

{{ rootPath }}

or

const Path = require('path')
eleventyConfig.addFilter("relative", function (url) {
  return Path.join(
    './',
    this.ctx.page.url.split('/').reduce((a, b) => a + (b && '../')),
    url
  )
})

{{ page.url | relative }}

@illycz
Copy link

illycz commented Jul 24, 2020

Thanks @mpalpha
I'm edited you solution little bit, because iť not working when the site is in folder.

module.exports = {
  rootPath: function(data) {
    return data.page.url
      .split('/')
      .filter(function(x) {
        return x;
      })
      .map(function() {
        return '../';
      })
      .join('');
  }
}

And then use it like this: {{ rootPath }}assets/styles.css

@mluce194
Copy link

mluce194 commented Dec 4, 2020

I am having the same issue since I am working with a Website hosted in a subfolder. I managed to change the urls for css stylesheets and thumbnails images, however I did not succeed in changing them for posts urls.

@michaelfig
Copy link

I put my solution for this problem, which is a mishmash of the other suggestions here, and fitting my own site's requirements at: https://www.npmjs.com/package/eleventy-filter-relative-url

@btjanaka
Copy link

btjanaka commented Dec 14, 2021

I came up with another solution which tweaks some of the solutions from here. It doesn't seem like filters get the this.page context, so I used a shortcode instead.

  eleventyConfig.addShortcode("url2", function (url) {
    if (!url.startsWith("/")) {
      throw new Error("URL is already relative");
    }
    // See https://www.11ty.dev/docs/languages/liquid/ for more info on page
    // variables.
    const relativeUrl = path.relative(this.page.url, url); // Use page.url instead of page.filePathStem
    return relativeUrl;
  });

Usage:

{% url2 "/your/absolute/url" %}

@graphicore
Copy link

Thanks @mpalpha and @illycz

I put your rootPath solution directly into my eleventy.config.mjs.

    eleventyConfig.addGlobalData('eleventyComputed.rootPath', ()=>{
        return data=>data.page.url
                .split('/')
                .filter(x=>x)
                .map(()=>'../')
                .join('');
        }
    );

usage : {{ rooPath }}assets/styles.css

Note that the function passed to eleventyConfig.addGlobalData('eleventyComputed.rootPath' returns itself a function, it's documented.

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