gatsbyjs / gatsby

The best React-based framework with performance, scalability and security built in.
https://www.gatsbyjs.com
MIT License
55.2k stars 10.33k forks source link

Themes system? #2662

Closed chadwatson closed 5 years ago

chadwatson commented 6 years ago

First of all, Gatsby is changing my life. Thanks for all your work, guys.

I looked around and couldn't find any clear indicators that there is a theme system in the current version (1.9.82). I found this page in the docs, but it doesn't give any instructions for how to create a theme.

If it is a thing, could someone point me in the right direction? If not, how can I jump in and help bring it to fruition?

nodox commented 6 years ago

Nope there is no theme system in place as of now. I'm working on one independently and a lot of gatsby under the hood magic is causing friction, mostly in how routing is being down. @KyleAMathews would love you thoughts on what a theme development ecosystem might look like so the community can bring it too life.

KyleAMathews commented 6 years ago

Starters are basically themes. Depending on how you look at it.

What do you mean when you say "theme"? Before we can build a theme system we have to decide what we mean by it :-)

Same with you @nodox — can you define what you mean by a Gatsby "theme"?

nodox commented 6 years ago

I would say a theme is an isolate collection of components and css that I can drop into my currently existing project without having to clone a whole new gatsby project. It can be a NPM module or a git submodule.

KyleAMathews commented 6 years ago

What are some examples of this? E.g. use cases you or others would need?

chadwatson commented 6 years ago

My use case is that I have a client that wants two sites that are exactly the same except for colors, fonts, and content. It’s not ideal to maintain two separate code bases. Something like what is described in this doc would be perfect.

KyleAMathews commented 6 years ago

Cool — looks like we all have the same idea haha :-)

Yeah, I think of themes as a composite of components & Gatsby plugins so you can drop e.g. a "blog theme" into an existing Gatsby site and it'll add everything you need to start blogging.

The really tricky part though is figuring out to make these themes easily customizable w/o making them upgradable. Ideally for example there'd be a gatsby-theme-blog which a really high % of Gatsby blogs could be based on. But to do that there needs to be a really clean and maintainable way to tweak the output without cutting yourself from upstream improvements.

nodox commented 6 years ago

Do you mean gatsby-theme-blog would be a base plugin where you tweak stuff in or would the theme be the name of the specific plugin?

I would almost find it easier to expose blog specific APIs for those users that want to use gatsby for blogging on the whole site or a specific directory. Then theme developers can develop around those endpoints and drop it in once they are done and it'll work. This establishes the separation of concerns you were talking about.

What do you think? @KyleAMathews?

KyleAMathews commented 6 years ago

"theme" means it's a new type of plugin basically. So you can add 1-N themes to your gatsby-config.js which encapsulate plugins/components necessary to solve a use case e.g. adding a blog to your site. Ideally too is that themes could build on other themes. So have "base" themes that then more specific themes build on top of.

expose blog specific APIs

Gatsby is a general-purpose framework so there won't ever be any "blog specific APIs". Though I'm also not sure what those would be since what a blog needs is largely the same as what ecommerce, marketing, documentation, etc. sites need.

nodox commented 6 years ago

I have a repo focused on gatsbyjs blogs with drop in themes that we can use as a case study once its done.

victorhooi commented 6 years ago

Just wondering if there was any update on themes in GatsbyJS, or what direction you think this might take? =)

nodox commented 6 years ago

After many months, Gatsby Manor is my attempt at this feature request.

Read this article to understand what it is, how it works, and how to contribute. I ❤️ GatsbyJS!

jbolda commented 6 years ago

I did a bit of riffing on how this might come together. I like the idea of composing layers within a theme. I also think it makes a lot of sense to import each of these from npm with the ability to "eject" out of each layer either in partial or whole as needed. With v2 planning to remove layouts and encourage the use of higher order components, it makes a lot of sense to head this direction with themes as well.

structure

The top level part of the theme, gatsby-theme-bulma, just imports the global css. The next layer is gatsby-theme-bulma-layout which sets the nav items that you would typically see in v1 gatsby layouts. It is entirely possible to have mutliple types of layouts that the user can choose between just by adding a key to their config (not currently implemented). The lowest level is likely thought of as the page level, and may have mutliple theme plugins for it. I choose to try gatsby-theme-bulma-blog first off (can you tell I am just ripping pieces out of my blog?). I believe, once you hit the page level, it can start having some opinions on your website folder structure. In this case, I am expecting markdown, and will convert any markdown in src/blog. Once the opinion gets this specific, we open the possibility of actually implementing a template and gatsby-node.js to run that template. I might also expect to see, at this "level", a gatsby-theme-bulma-homepage, gatsby-theme-bulma-gallery, gatsby-theme-bulma-ecommerce, gatsby-theme-bulma-contactus, etc. At the end of this, a user can add a few plugins, a folder full of content in markdown and have a solid website.

gotchas

gatsby-config

Takeaways, it may be useful to allow plugins to set items within gatsby-config.js. This would let plugins import and define underlying plugins without requiring the user to know about it. Right now I have to specify gatsby-plugin-sass even though gatsby-theme-bulma is technically the thing using it.

graphql

It would be really nice for the *-blog to make and specify the template, but gatsby doesn't extract queries from node_modules. Should we solve this by extracting queries from any template specified in gatsby-node.js in createPages? So as it stands right now, we can only make a theme that is a bunch of components with opinions on what data it is expecting.

fragments and "global" data

Ok, this is kind of the same as in graphql, but thought I would mention it. It would be nice to have global graphql especially for the site data rather than having to pass it the Xth layers of components.

babeling

Right now we don't babel these components so the npm modules need to themselves. Not an impossible task, but more involved to make sure we babel the same as the main gatsby repo. Also, how do we deal with the graphql? Do we just need to make sure that babel ignores the graphql export at the end so that gatsby can deal with it?

tentative proposal and RFC

I believe if we enable gatsby to extract queries from any template specified in graphql, this will solve the biggest issue. It may be useful to create a method to specify a folder(s) in node_modules to babel for you (because components with graphql need to ideally be extracted first). Lastly, I am still tempted to say using context for global queries would be super useful (as I originally mentioned in this RFC).

Does anyone else have any thoughts or considerations on how to handle this? @KyleAMathews, is extracting queries from node_modules folders in this manner even reasonable?

rstacruz commented 6 years ago

Hey there :) Hoping to chime in with my thoughts on why I really would love for this to happen.

brandonkal commented 6 years ago

Here's my thoughts on themes - keep it really simple. Inside your Gatsby project you have a themes folder. Inside of that you can place one theme folder e.g. my-theme. That folder would basically contain the contents of the src folder as it is now.

Before build the theme folder and src folders are consolidated by Gatsby so that the contents of themes/my-theme are used.

In this way one could use a git submodule. Then you could have 3 blogs with the same layout all defaulting to use themes/my-theme. If one specific site required a different about.js component it could be copied and placed in src. That would override the theme default about.js at build. But every other component shares one codebase.

selrond commented 6 years ago

Coming from WordPress world, they have a solid system of Child Themes.

Maybe we could get some inspiration on how to implement / standardize something like that in Gatsby.

brandonkal commented 6 years ago

@selrond I believe something like this could be accomplished by following the Hugo system of themes. Themes exist in a folder and can be overridden/customized by adding similar components in the src folder.

This is very much like I described above. See this as an example: https://gohugo.io/themes/customizing/

JamesTheHacker commented 6 years ago

It's such a shame that Gatsby doesn't have a theming system.

Wordpress, Hugo, Jekyll etc. all have a theming system in place and it's a big selling point. For many freelancers having a base theme to start with is a huge help. Especially when the clients budget is unable to cover design.

How about using something like styled-components? That has a theming system in place: https://www.styled-components.com/docs/advanced

selrond commented 6 years ago

@JamesTheHacker styled-components' Theming you referred to is something different. Its' purpose is for components to be able to access theme object through React's context API, regardless of where they are in the component tree.

JamesTheHacker commented 6 years ago

Ah. Apologies I was incorrect.

S1ngS1ng commented 6 years ago

I think what @brandonkal mentioned in https://github.com/gatsbyjs/gatsby/issues/2662#issuecomment-387703090 would be a good idea.

Personally, I am using Hexo for my blog since 2016. Due to "some" reasons, I'd like to re-build my blog with Gatsby. This is my first week with Gatsby, lots of fun 😃

The way how Hexo manages its theme is exactly as @brandonkal mentioned above (I assume Jekyll is doing that in a similar way). Theme stays within the project under themes directory as a git-submodule, while user content stays in a separate directory (named source).

As a user, I found that convenient whenever I need to update the theme based off upstream. It also provides the user with more flexibility, say, a user could fork their own version and add their own commit on top of it (the way I do it). Next time when upstream updates, simply rebase to get the user's copy synced up (based on the assumption that user commit is not too much, normally just some tweaks or customized style).

Here is the link to Hexo themeing guide: https://hexo.io/docs/themes

DavidSabine commented 6 years ago

Hi,

I don't want to muddy the waters... but...

Any discussion of themes ought to also include discussion of theming based on routes or domains or sites. For example:

At http://localhost:8000/___graphql:

Perhaps I'm selfishly trying to solve for an acute problem that I face -- but I feel I should be able to do this with relative ease:

http://ONE.site.localhost:8000/ -- display with theme 'A'. A theme probably includes, at a minimum, some typography and overall visual layout and basic visual style. Maybe a theme also defines a locale/language (or can have language children) like http://ONE.site.localhost:8000/en-us/

http://TWO.site.localhost:8000/ -- display with theme 'B'.

http://site.localhost:8000/THREE/fr-fr -- display with theme 'C' with French localization.

If anyone has solved for the above, please let me know!

brandonkal commented 6 years ago

@DavidSabine if you are serving from different domains, you are probably looking at different applications. If it is important that they be visually distinct with no shared design, why would you want them combined? Just build two apps and develop seperately. The content backend could be the same.

DavidSabine commented 6 years ago

Hi @brandonkal, great question and understand your point. And, I think what you mean by 'app' is 'code repo'. (Or do you mean to have multiple 'apps' within a single codebase -- if so, disregard the following and please elaborate.)

Here's some more detail...

Let's say a multi-national product manufacturer has had a Drupal site published at 113 domains worldwide for the past 10 years. Those domains follow these patterns (exemplified here to show their inconsistencies):

www.company.com (defaults to USA) canada.company.com (same theme as above, but shows a Canadian version of logo instead of USA logo; everything else is identical) canada.company.com/fr (same as above, but displays French content instead of English) company.co.uk (same theme as above but currencies are displayed differently) empresa.com (same theme as above, but displays Spanish language and colours are different to match the marketing strategy for the company's operations in Spain) ...and so on.

Let's say the team has decided to incrementally move toward Gatsby. (Let's say) they've decided to pull content from the drupal site and start with 1 country (Spain, for example) as a proof of concept and to prove to stakeholders that Gatsby is in fact faster than Drupal's front-end AND can be styled appropriately. When the stakeholders see the site running smoothly in Spain, they ask the team to take the same approach for the USA site: www.company.com

Should the team create a new app and maintain one each for Spain and USA? Perhaps... but they know there are likely to be 109 more of these and 90% of them share the same design, same assets, same layout -- in most cases, the only thing which differs is the domain name and the Google Analytics id. But they'll spend the next 4 months deprecating each of the 'sites' currently published by a single Drupal multi-site instance.

It wouldn't make sense to have different apps for each of the above... (if what you mean by 'app' is 'code repo'). The team thinks of the problem as 'one system' -- which exposes itself to multiple domain names.

Disclaimer: the case above is real (but a fake company name of course). All the domain names pointed to the same Drupal instance which was on a few load-balanced AWS EC2s. Based on HTTP request, Drupal would response with appropriate content, language, and cookies. Theme was the 99% the same for all countries.

Disclaimer: My brain is still wrapping itself around 'package management' -- so maybe the problem is solved by other means and I just don't see it yet.

Also: I acknowledge that Gatsby doesn't intend to be a replacement (exactly) for Drupal -- that's not why I chose the example above. I chose the example above because it was real customer in my past AND I really think my team would have enjoyed Gatsby for that project more than they enjoyed Drupal.

brandonkal commented 6 years ago

@DavidSabine Wow, that project sounds like a nightmare. Service workers and Progressive web apps get very tricky across that many domains which is part of why I suggested an app for each domain.

In your case it sounds like the designs are mostly the same. Things such as the logo could serve a different asset localized asset based on geoip or the client can request the correct logo based on its i18n setting. Currency symbols and language could also be handled by Gatsby with i18n.

My suggestion was to use multiple apps. By app I mean the progressive web application that the client downloads when they visit a site built with Gatsby. This doesn't mean you have to use multiple repos. One option that comes to mind is to write a script to run gatsby build iterating over different gatsby-config.js files (or env files that define the variable bits that are included in gatsby-config.js). Then each app can be deployed to an edge server closest to its target geo. For 2-3 sites it is a simpler than adding a bunch of conditional logic to the app for changing things such as color, font sets, etc...

For 100+ domains..., well that changes things as I can see. The graphql thing would be interesting but it still seems inevitable that multiple apps would need to be built unless all conditional logic could be done client-side.

strogonoff commented 6 years ago

Just my two cents, @DavidSabine might do much better by addressing the multi-site setup issue from deployment automation/DevOps/SRE perspective rather than on app level.

In other words, you can have a Terraform project, or an Ansible playbook, etc., that automates the provisioning of a network of static sites.

Each site would have its own repo, but the repo can be made really minimal, as long as shared appearance can be encapsulated in a Gatsby theme. Ideally a site would only provide a few settings, such as the domain name and/or base path prefix, and override content as needed (e.g., to provide marketing copy in different language).

This sort of multi-site setup can differ drastically across projects and organizations, IMO it doesn’t sound like Gatsby could feasibly support all variations of it…

m4rrc0 commented 6 years ago

@DavidSabine as a proof of concept I built more than 10 websites sharing a same repo. The theming (and site structure) is actually defined in the CMS. So all websites are different but sharing a same codebase. In your case I guess Drupal might not be the best place to define the theme but you could pick another source plugin and define the themes for all websites in some other place, even a specific github repo with all themes files for example. Then you just need some build logic and an environment variable to pick the correct files from that other source on build. Obviously @strogonoff knows a lot more than me about deployment infrastructure but that is the best answer I can give to help. ;) Good luck.

brandonkal commented 6 years ago

@MarcCoet that would be interesting to see. Is the proof of concept repo open source?

m4rrc0 commented 6 years ago

@brandonkal I haven't yet decided what I am going to do with it. It is not open source for now, sorry. You can see the result here: https://www.toile.io/portfolio/ The site itself is using that concept and all the colored bands at the end of the page are web links to sites using it. This project is more than one year old now and there are a lot of things I would like to change. I am in the process of rebuilding something from scratch and open source versions are in scope.

signalwerk commented 5 years ago

worth mentioning in this context; https://github.com/gatsbyjs/gatsby/pull/9517 thanks to @ChristopherBiscardi

ChristopherBiscardi commented 5 years ago

Thanks @signalwerk. I'm currently working on theming for gatsby, as the pull request above indicates. The current state is that we merged early experimental support for themes as described in #9517. Themes can be installed from npm, etc and are probably closest to WordPress' theme implementation (if you currently think of your site as the child theme and the theme from npm as the parent). It's pretty close to "any gatsby site is a parent theme" with the deviations from that being mostly plugins that assume incompatible paths internally (basically, these path handlings would be considered bugs where they were not before).

I'm paying attention to this thread, so feel free to leave comments here as we progress.

signalwerk commented 5 years ago

Thank you @ChristopherBiscardi for you work! this looks awesome! I read your post and I installed 1–2 gatsbys in the past but I didn't really understood how to use themes. I saw your repo but couldn't bring it to work. But I realised now with yarn it works. But not with npm. (see PR). It's actually really awesome!

gatsbot[bot] commented 5 years ago

Old issues will be closed after 30 days of inactivity. This issue has been quiet for 20 days and is being marked as stale. Reply here or add the label "not stale" to keep this issue open!

calcsam commented 5 years ago

We've now introduced Gatsby themes. Learn more here:

https://www.gatsbyjs.org/blog/2018-11-11-introducing-gatsby-themes/

https://www.gatsbyjs.com/gatsby-days-themes-chris/