Sessions is temporarily moving to YouTube, check out all our new videos here.

Best Practise Neos Setup

Roland Schütz speaking at Neos CMS and Flow in November, 2017
111Views
 
Great talks, fired to your inbox 👌
No junk, no spam, just great talks. Unsubscribe any time.

About this talk

We will discuss composer-friendly single-repository setups, folder structure and auto-mapping of template files and naming conventions. We'll also see a template for the Page fusion structure and how to override 3rd party packages.


Transcript


Hello, thank you all for being here. This is the third time we organised this Neos event together with David and Marcos, the guys in the back. Yeah, so I'll give a talk today about a best practise Neos setup. It's, on purpose, very opinionated, because it gives us a similar structure and it's very easy to get into to new projects because they all look the same. It's based on a lot of work from people you might know like Christian Miller or Dmitri or Dominique. And it's based on some of our own code conventions. Everything of that is open source and you can later check it out online. The first thing is our whole hosting with Dmitri is Alpine package, so it's Linux Alpine package. It's also opinionated and it provides you a full setup of a Neos project out of the box following some of the conventions and environment variables. And it also supports, out of the box, some rolling development, meaning if you integrated this continuous integration, it starts a new build of... Yeah, it starts a new build, tests it, and if all has passed, it puts it online. Very simple, Docker in port is pretty straightforward. Mainly you define a repository URL. It fetches from there and sets everything for you automatically. It also includes SSH access. For that you just need to define GitHub usernames and it takes the public keys from your GitHub repositories, from your GitHub profiles. Okay, now something probably you've been interested, something many of you might not know. There were two camps for a long time. There was a standard, single repository setup where you basically put your whole Neos package, including your site package into one GitHub repository. The big advantage of that is if you did a change in your site package, you had one commit in your Git repository and it was already simple and easy to update. There were a few drawbacks. The first drawback was Composer was not aware of your site package. So if you had a site package and in your site package you defined some requirement, Composer didn't care about them, it didn't find it. Because you include the site package directly in the main package. This led to another thing. You had define every dependency which you were using in your site package twice. You had a root composer JSON, where you defined exactly the package you needed. And then you had to, again, define it in your site package so that the loading order of Neos made sense. There was another approach, which was a two-repository set up. So basically you had one repository for your main package. And then you had one repository for your site package. And the main package loaded the site package's dependency. There were issues with that as well. The most obvious one, every time you changed code in your site package, you had to first change the site package, make a git commit there. And then, again, we had to do a git commit in your main repository where you updated the composer to lock. So this is a new approach. It comes from Christian Miller and it's a single site repository, and combines both advantages. So what it does here... In your Composer, you define your site package as a dependency, but then here in repository you define that site package as a pass, which then means that you have everything in one repository, but still Composer evaluates all the dependencies. And that brings you the big advantage that instead of having here, oh, sorry. Instead of having here 10 requirements, which you then always duplicate in your site package. You have only your site here. And everything else is in your site package. Yeah, so all of these dependencies. Okay. Yeah, here as well. Makes the repository cleaner and it supports Composer and, yeah. Then there a few tips we found are very useful. If you always name your site package the same name, it's very easy to copy/paste note types from one package to another, because you always have the same namespace and you don't need to change each file. So read consistently have it CodeQ:Site and you want to have your Company:Site, site package as like name which you always you. And it's also very nice to have a front-end folder where you have all your front-end assets, JavaScript, CSS, everything in there, which is very easy for you to then maybe use it in some other non-Neos projects as well. Just something we had a few times. So now we have file name conventions. There are many approaches out. There are many different ways people do it. And this one is very much inspired by Dmitri's best practise, so Dmitri and Dominique. The basic idea is when you create, let me first go to the node type. If you create a note type, you would put the YAML document in a file called NodeTypes.Content or Document, whatever type of node type you create, which makes it more easy to see what's going on here. And then use the node type name here. And for each node type, use a separate file. I think this is most best practise. Many people do that. And here it's been more opinionated. We have in Resources/Private/Fusion. We always create one folder for each node type. And in that we have a Fusion file and in most cases an HTML file, depending on how you implement the fusion. And here then here's also to always use that same node type. I'll go into details why we do that later, except from general readability. And it always works out nice for us when we're always supporting the attributes. Because it's later easy to just add a process function if you need some special classes on your node type. So beside that, there's the concept of components. I'm not sure how much, how deep you are into it. How many of you guys know components? How many of you use partials? Okay, so since, I don't know, probably a year, well, right now the best practise is to use components instead of partials. It allows you to better decouple the logic and include fusion and HTML. Right now only into the filing convention. So we do the same structure as you've seen with node types. Of course, a component does not have a YAML configuration because it's not a node type. And we put everything in a folder called components. And this gives us reusable components which we then can use in multiple node types. And if you want to go even a step further you should look into Atomic Fusion, which we on purposely did not use right now yet because it's quite a big overhead, like from the learning side, for new people. Yes. And now the cool thing is if you're always following these configurations, we can use a generator which automatically maps our Fusion object names to file names. So I'm never, ever defining a template pass anymore, because it's always based on convention and automatically created by generators. Okay, so everybody with me so far? Great, okay. I have a few more opinionated conventions about node types. The first one is that you should put all logic into Fusion. You can have some render rags and everything in HTML, but the logic should be in Fusion. This is like new best practises. And if you don't know it yet, check out, there's a really good talk from the last Neos Conf about that topic. Then there's, I'm not sure if it's that clear, this topic here. If you want to have a reusable code in your YAML files, there are two options. You can either use mixins, which looks basically, let me show you. So a mixin would look something like this. I'm defining a title mixin. And basically I'm defining one property. It's called Title and it has some configuration. And then instead of redefining this multiple times, I can just include it like this. And I'll switch between title and text. But you get the idea. So I'm only defining the property once and then reuse that multiple occasions. The big advantage of that is that you have to do this complex lower configuration only once, and then through mixins you always use the same. There's another way how you can not copy/paste it all the time, and this is called YAML references. The only problem about YAML references is that they do not work across multiple files. And so you end up with a lot of copy/pasting as well. And that's why we decided to only go with mixins, or not only, but to normally go with mixins, and prefer them over references. Something which works very well for us as well is to have one, to always have one mixin called text, which is a general text property, one which is title, which then has a, by default, a headline and it's a typical headline or title. And then we have one called plain title, which basically removes all the lower configurations. So you cannot configure any font weight or any styling. It's just plain text. But these are editable with a lower. Okay. Yeah, so that's about mixins. Then if you have external node types, the best is always to inherit and make, not inherit, to create one for yourself. So if you would use a package and it provides you a YouTube helper, a YouTube node type, but you want to have a slightly different behaviour, it's better to create a node type for yourself and just inherit, in Fusion or in YAML, wherever you need. If you're really lazy and you go to shameful but easy way, you use this convention where you call your YAML files, NodeTypes, dot, and then use the package name. So NodeTypes.Package, for example, for the Neos node types package, and then the node type name, which gives your clean or what you're actually extending, and something which people who do more probably already know, if you include other packages and they provide some node types which you do not support in your theme because it will look weird or you just don't need it, always set them with abstract: true to disable it for the user. Okay, and there's this small, but I don't know, for some reason I really care about this, because I find it so ugly otherwise. If you have node type and it allows you to create multiple elements beneath, but only one level, instead of creating a child node, which then is the content collection and then has even more nodes, and you have this long structure, just make it a content and a ContentCollection, and then you can have it directly based. Okay. The Neos Skeleton I have includes layout mechanism. And I just want to give you a short idea about that. There are many projects which use a similar system. If you want to go in details, you can check it out later, it's open source. The basic idea is to use this kind of snippet here. And what it will do is for each document node type, it will follow the paths, depending the node type. And then if you create an, let me see, one second. If you create, for example, a home page, what you would do is you would define one called homepage.document, which is the configuration for the document. And then you have one which is just homepage, which would include the main content area. Yeah, so we... So we have separated the whole logic which you want to use in multiple packages... We've separated logic which you want to use in multiple document node types into two distinct Fusion files, the one we call abstract page. And this is basically used for every page we render. So in that simple example, every page which we create will include a CSS file from that source and JavaScript file from that source. And it will then initialise a few packages. And then we have a layout and that layout mechanism can be switched out by different layouts. This is a default layout and it's very simple. First, it gets a component called header, renders that, then it gets the content, which is the main content, the thing you define here in this block. So this is the thing which normally differs, depending on your document node type. And in the end you render a footer. So that's pretty straightforward. And in my project, of course, you'll have different layouts. So you don't only have a default layout, you have a home-based layout, or you have some kind of special arrangement where you have different footers or no footer, or whatever. Okay, the big learning here is, and this is actually well documented on the Neos documentation as well, to use this kind of layout mechanism in contrast to the old one. That was a bit confusing maybe. Yeah, in contrast to the old one. I'm not going into that, because it's not interesting anymore. Just go with this one and it's documented in Neos documentation very well. Good. This is some small thing. If you have JavaScript, you always need to take care that in your Neos backend, the page still works the same way. And that means that in the backend, your pages are loaded via AJAX, and therefore the normal load events are not triggered anymore. So if you open the Neos backend and then you change pages, it doesn't trigger the normal JQuery-ready and JQuery-loaded events, or whatever library you're using. So what you should do is have some abstract init file. And that init file is triggered, of course, first on document loaded. But then also every time Neos.PageLoaded. This is something we have to care about only a bit more time, because soon you'll have the react backend and then we don't have to care about this anymore. Yeah, but just follow this pattern and it will just work, yes. Okay, so also we, by default, included all of project packages. Many of you probably know those. The SEO package, the redirecthandler package, which on one hand creates automatic redirects for every time you change the document name, I'm sorry, the page name in the Neos backend And also it allows you to create redirects with the console. The Neos Google Analytics package, the moc/notfound. It basically gives you an option in the backend to create a page called 404. And then every time a user enters a invalid URL it will redirect to this 404, which you define at a backend. There's on package called image optimizer, which automatically shrinks your pictures, which is really nice if you're not yet using some kind of, how's it called? The Google optimizer? There's a page feed module. If you don't have that in your setup, this is really helpful because it just runs JPEG or PNG compression on the source files, which can be like 30% up to 50% smaller. So that can be very huge. A few more useful things. Many people still use the Neos node types package. And the biggest use case for that is probably a content references. And I just separated out into a package which only does those counter references. There's also a pull request pending to separate this out in the original Neos node types package. So if you are interested you can also plus one the pull request, and then we soon have official content references package, which is not dependent anymore on the other node types. A really nice helper is carbon/link. It allows you to easily make links which are automatically either external or internal depending on what you're linking to. So if you link to another node your page, it will be a normal link. If you link to an external URL it's automatically target blank, which is nice. And there's one package called eel shell, where it can easily try out some eel code in your console when you're writing eel code. So during development that's helpful. Yeah, I mentioned the image optimizer. It also includes a Unicode normalizer, which is a really annoying small thing. If you copy/page text out of PDFs, you often get the Germanwrong. And there are a few other things, but that's the main issue. And this packages automatically normalises it for you, because you'll normally not find that issue in all browsers, except IE, it's done very well. And in IE you have just broken text. And we're also using the cache-breaker. For that, we'll soon switch to the flow pack cache breaker. And then my Neos Skeleton also includes a few Code Q specific stuff which you are probably not so interested into. We use a continuous integration with CircleCI and the script is included in the package. And we use exception monitorings through Graylog. Yes, if you're interested, go into the code, see what you like, what you don't like, fork it, copy/paste. Feel free to use whatever you want. It's based on a lot of open source work from other good Neos developers. So feel free to steal everything.