Change site.url to localhost during jekyll local development
Asked Answered
F

2

87

My jekyll blog template have links to resources and pages like so:

{{ site.url }}/my-page.html

This works well in deployment, but when I run jekyll serve in development, all of the links point to the live page instead of the development page.

my-site-url/my-page.html

# But I want this in development
localhost:4000/my-page.html

Is there a way to make jekyll use a different {{ site.url }} in development?

Fern answered 9/12, 2014 at 18:28 Comment(0)
P
135

This is a common problem between different Jekyll environments.

Some explanations

We need to understand site.url and site.baseurl and in which situation we need them. Those variables don't serve the same purpose.

site.url

By default, this variable is only used in page head for the canonical header and the RSS link. It's also used in the xml feed to point to site resources as the software that will manage this feed doesn't know resource's urls.

This variable is only necessary for external systems.

site.baseurl

This variable indicates the root folder of your Jekyll site. By default it is set to "" (empty string). That means that your Jekyll site is at the root of http://example.com.

If your Jekyll site lives in http://example.com/blog, you have to set site.baseurl to /blog (note the slash). This will allow assets (css, js) to load correctly.

See how assets are loaded in you head :

<link rel="stylesheet" href="{{ "/css/main.css" | prepend: site.baseurl }}">

that can also be :

<link rel="stylesheet" href="{{ site.baseurl }}/css/main.css">

Working in different environments

Now you have to test your site locally and to deploy it in production. Sometimes, the baseurl is different and the jekyll build may not work out of the box in one of those environment.

Here we have two solutions :

Use jekyll serve

Let's imagine that your site lives in a github repository and is served at https://username.github.io/myProject.

You can setup the baseurl to /myProject. and test your site locally with jekyll serve, your site will be served at http://127.0.0.1:4000/myProject/

Use multiple configuration files

If, for one reason or another, you cannot use jekyll serve, you can set a configuration file for both environment and jekyll build depending on where you are deploying.

Let's say we have the local site served at http://localhost and the production site served at https://username.github.io/myProject.

We leave the _config.yml with url: https://username.github.io and baseurl: /myProject

We create a new _config_dev.yml with only url: https://localhost and baseurl: ""

Now to test locally :

jekyll build --config _config.yml,_config_dev.yml

or

jekyll build --config _config.yml,_config_dev.yml --watch

When pushed on production, the jekyll build command will use the default _config.yml.

Polyglot answered 10/12, 2014 at 11:53 Comment(13)
For some reasons, the a pre-made jekyll theme I downloaded use site.url to prepend the css / js resources. Is this a bad idea? Should I change everything to site.baseurl, and use site.url only for canonical link and xml feed?Fern
Of course ! {{site.baseurl}}/asset for assets and {{site.url}}/{{site.baseurl}}/ressource for external needs. And maybe you can approve my answer.Polyglot
Perhaps {{ site.url }}{{ site.baseurl }} instead since site.baseurl already has a pre-pended slash?Fern
You're absolutely right, it's {{ site.url }}{{ site.baseurl }}.Polyglot
But why it does not append /blog to post URL? I still get the broken URL of the post like /2014/12/12/mypost-name. It actually broke the link since i have everything inside blog folder.Colucci
Jekyll doesn't prepend site.url automatically to post.url. You have to do it yourself : {{ site.url }}{{post.url }}Polyglot
@DavidJacquel How about we set site.url to http://requestly.github.io/public and define another variable in config like site.rootUrl to http://requestly.github.io. Because there are so many references in the theme which needs to be updated. Do you see any problem with this approach. I am wondering why theme designers did not use baseurl by default. There should be some reason behind that.Kamilahkamillah
I have the same question and I don't think the accepted answer actually answers it. Is it possible to access the host and port of jekyll serve from inside the generation logic? This would be especially useful if you use jekyll serve --host myhost --port 1234.Participation
@basszwo the answer is yes. But, you can take time to ask a real question on SO ; I'll be pleased to give you an real answer.Polyglot
@david-jacquel Here ya go! #32488383 Looking forward.Participation
I came to this question because I had the opposite problem. After reading this answer, I realized that jekyll build uses the production url, whereas jekyll serve will use localhost (regardless of what the url setting is in _config.yml). Hope this helps someone!Scurf
jekyll build --config _config.yml,_config_dev.yml: first one for prod, second for dev? It should also work with serve in dev: jekyll serve --config _config_dev.ymlMata
I used jekyll serve --config _config.yml,_config_dev.yml. For url I used: http://localhost:4000Slantwise
S
0

The question and the good answer is a bit old, but I think still from need.

I also run in that issue on jekyll v4.2. I have three differnt environments, with differnt url and baseurl in my config-files (see answer from @david-jacquel) can be combined.

Production Dev GitLab Page
url https://company.tld http://localhost:8017 https://n13org.gitlab.io
baseurl / / /demo/company-tld
config _config.yml _config.dev.yml _config.gitlab.yml

I was not happy with the handling / behavior of url and baseurl together with CSS / JS / images / internal links to posts and pages ... I tried many ways also in combination with the relative_url filter.

I end up, with writting a small ruby plugin for jekyll. The plugin is just ruby code inside the _plugins folder.

The plugin code from file tag_website_url.rb will create a new jekyll tag which can be used in html or markdown (md) files with {% website_url %} or {% website_url noprotocol %}. The second tag will omit the protocol (e.g. http or https).

require 'uri'

module Jekyll
  class WebsiteUrlTag < Liquid::Tag
    def initialize(tag_name, text, tokens)
      super
      @text = text.strip
      tokens = tokens
    end

    def render(context)
      site = context.registers[:site]

      uri = URI.parse("#{site.config["url"]}#{site.config["baseurl"]}")

      str_uri_port = uri.port && uri.port != 80 && uri.port != 443 ? ":" + uri.port.to_s : ""
      websiteurl = uri.host + str_uri_port + uri.path
      websiteurl.prepend(uri.scheme + '://') if @text != "noprotocol"

      websiteurl.sub(/(\/)+$/,'')
    end
  end
end

Liquid::Template.register_tag('website_url', Jekyll::WebsiteUrlTag)

The code can handle also PORTS which are often used for localhost development. The ports 80 (http) and 443 (https) will be removed. The settings from the config files are stored inside the variables site.config

Sardinia answered 29/9, 2021 at 4:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.