1<!doctype html> 2<html lang="en" dir="ltr"> 3<head> 4<meta charset="UTF-8"> 5<meta name="viewport" content="width=device-width,initial-scale=1"> 6<meta name="generator" content="Docusaurus v2.0.0-beta.6"> 7<link rel="alternate" type="application/rss+xml" href="/blog/rss.xml" title="Cromwell CMS Blog RSS Feed"> 8<link rel="alternate" type="application/atom+xml" href="/blog/atom.xml" title="Cromwell CMS Blog Atom Feed"><title data-react-helmet="true">Blog | Cromwell CMS</title><meta data-react-helmet="true" property="og:title" content="Blog | Cromwell CMS"><meta data-react-helmet="true" name="twitter:card" content="summary_large_image"><meta data-react-helmet="true" name="description" content="Blog"><meta data-react-helmet="true" property="og:description" content="Blog"><meta data-react-helmet="true" property="og:url" content="https://cromwellcms.com/blog"><meta data-react-helmet="true" name="docusaurus_locale" content="en"><meta data-react-helmet="true" name="docusaurus_tag" content="blog_posts_list"><link data-react-helmet="true" rel="shortcut icon" href="/img/icon_small.png"><link data-react-helmet="true" rel="canonical" href="https://cromwellcms.com/blog"><link data-react-helmet="true" rel="alternate" href="https://cromwellcms.com/blog" hreflang="en"><link data-react-helmet="true" rel="alternate" href="https://cromwellcms.com/blog" hreflang="x-default"><link rel="stylesheet" href="/assets/css/styles.adf4fe22.css"> 9<link rel="preload" href="/assets/js/runtime~main.a8162b3a.js" as="script"> 10<link rel="preload" href="/assets/js/main.78c54909.js" as="script"> 11</head> 12<body>
13<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){var t=null;try{t=localStorage.getItem("theme")}catch(t){}return t}();t(null!==e?e:"light")}()</script>
13<div id="__docusaurus"> 14<div><a href="#" class="skipToContent_QVmC">Skip to main content</a></div><nav class="navbar navbar--fixed-top"><div class="navbar__inner"><div class="navbar__items"><button aria-label="Navigation bar toggle" class="navbar__toggle clean-btn" type="button" tabindex="0"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><a class="navbar__brand" href="/"><img src="/img/logo_small_black.svg" alt="Logo" class="themedImage_3EHU themedImage--light_heW6 navbar__logo"><img src="/img/logo_small_white.svg" alt="Logo" class="themedImage_3EHU themedImage--dark_6pZL navbar__logo"><b class="navbar__title">Cromwell CMS</b></a><a class="navbar__item navbar__link" href="/docs/overview/intro">Installation</a><a class="navbar__item navbar__link" href="/docs/development/theme-development">Development</a><a aria-current="page" class="navbar__item navbar__link navbar__link--active" href="/blog">Blog</a></div><div class="navbar__items navbar__items--right"><a href="https://github.com/CromwellCMS/Cromwell" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link"><span>GitHub<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_OX1T"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></span></a><div class="react-toggle toggle_pM6S react-toggle--disabled"><div class="react-toggle-track" role="button" tabindex="-1"><div class="react-toggle-track-check"><span class="toggle_5Cll">ð</span></div><div class="react-toggle-track-x"><span class="toggle_5Cll">ð</span></div><div class="react-toggle-thumb"></div></div><input type="checkbox" class="react-toggle-screenreader-only" aria-label="Switch between dark and light mode"></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div></nav><div class="main-wrapper blog-wrapper blog-list-page"><div class="container margin-vert--lg"><div class="row"><aside class="col col--3"><nav class="sidebar_drON thin-scrollbar" aria-label="Blog recent posts navigation"><div class="sidebarItemTitle_+zDs margin-bottom--md">Recent posts</div><ul class="sidebarItemList_L38e"><li class="sidebarItem_iLZw"><a class="sidebarItemLink_Y3HD" href="/blog/intro-cromwell-cms">Introduce Cromwell CMS</a></li></ul></nav></aside><main class="col col--7" itemscope="" itemtype="http://schema.org/Blog"><article class="margin-bottom--xl" itemprop="blogPost" itemscope="" itemtype="http://schema.org/BlogPosting"><header><h2 class="blogPostTitle_XRV4" itemprop="headline"><a itemprop="url" href="/blog/intro-cromwell-cms">Introduce Cromwell CMS</a></h2><div class="blogPostData_cftJ margin-vert--md"><time datetime="2022-03-27T10:25:21.893Z" itemprop="datePublished">March 27, 2022</time> · 8 min read</div></header><meta itemprop="image" content="https://cromwellcms.com/img/blog/1_YD27_slzjBjcCuyifHciMQ.jpeg"><div class="markdown" itemprop="articleBody"><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_XX5z" id="motivation"></a>Motivation<a class="hash-link" href="#motivation" title="Direct link to heading">#</a></h2><p>Jamstack is out for a while. For most of us (developers) statically pre-rendered React websites are no wonder: page routing in the browser, âblazing-fastâ (as they usually call it) experience, etc. Try Gatsby or Next.js and youâll have it. If you are a web developer, you know React and probably know to do something with it. But for many normal people, it still looks like some expensive product they can live without. </p><p>78.9% of the internet is still on PHP. Well, a lot of these websites are old and these days developers choose PHP not that often. But for WordPress (39.6%) the number is always growing. Type in Google âE-commerce CMSâ and you will get good old-timers with some advices on removing reliance on developers. 15Meanwhile many modern Node.js CMS go the other way, the headless. If you want a frontend, be ready to hire a developer. Oh, it will cost you. 16Or if your Node.js CMS is not just headless then where do I click to install a plugin? Well, many of them donât support such plugins. </p><p>But a lot of non-programming people want an independent platform that they can simply manage and customize by themselves. Thatâs one of the major reasons that makes WordPress still so popular. Otherwise, everyone will just hire a developer to make a super fast and cool website.<br> 17Despite the advantage of Node.js, full-stack Javascript / Typescript, SPA and so on, people still stay on LAMP stack. And not because itâs the best, we can blame it for many problems. In one article I read author was comparing Wordpress and Ghost CMS. He was blaming Wordpress of being slow and insecure because of its plugins, and since Ghost CMS doesnât have plugins itâs better by both points. But I donât think an absence of potentially useful feature can be considered as an advantage. </p><p>If only existence of a plugin feature is a problem, then the problem is in the core design of CMS, not in a plugin. On the other hand, if
17CMS doesnât support extensions, then again, something is wrong with core design of CMS, because this CMS wonât be future-proof in my opinion. </p><p>There has to be a solution that can encompass all modern bleeding-edge techs. Statically pre-rendered React for frontend, mature and maintainable backend (look at Nest.js and TypeORM for example). GraphQL API that shines in CMS development where end users can build any type of frontend.<br> 18But I couldnât find the same level of versatileness, extendability, power in building plugins along with powerful GUI everyone can handle that WordPress provides. Thatâs how I ended up working on a side project most of my free time for past two years. </p><p>Today I decided to go public with the project, so Iâm introducing it: Cromwell CMS. You can find some example websites at: <a href="https://cromwellcms.com/docs/overview/intro#examples" target="_blank" rel="noopener noreferrer">https://cromwellcms.com/docs/overview/intro#examples</a> 19CMS is free and open-source, you can check the code or give at a star <a href="https://github.com/CromwellCMS/Cromwell" target="_blank" rel="noopener noreferrer">https://github.com/CromwellCMS/Cromwell</a></p><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_XX5z" id="core-design"></a>Core design<a class="hash-link" href="#core-design" title="Direct link to heading">#</a></h2><p>Node.js environment pretty much conveniently came up to a package system. Everything is a package. One like another can be installed via simple npm command and downloaded into flat node_modules structure. 20Following the tradition, Cromwell CMS is a set of packages and services that can be installed and launched independently. It inherits the advantages of microservice architecture, and itâs much easier to update the CMS simply via running one npm or yarn command. </p><p>I can also call it headless CMS because itâs possible to run API server with any custom frontend. 21So there are 4 main services:</p><ol><li>API server service. API server is written with Nest.js and TypeGraphQL, REST API for transactions, GraphQL for data flow. Both types of API are extendable by plugins (about it below).</li><li>Frontend service (Next.js). Basically, it is a custom Next.js server.</li><li>Admin panel service. Serves files of admin panel.</li><li>Managing service. This service is launching, watching, and restarting other services on user GUI input. For example, itâs easier to change a theme in WordPress, but with Next.js we have to restart the server with another app build. Well, itâs not common to restart servers as part of production lifecycle, but in my tests it is quite stable, I believe that can work with proper handling.</li></ol><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_XX5z" id="theming-engine"></a>Theming engine<a class="hash-link" href="#theming-engine" title="Direct link to heading">#</a></h2><p>All themes are npm packages. Just install a package with specific property in package.json and CMS will recognize it and display a theme in the admin panel. Then a user can pick a theme and CMS will take ready app build from theme package in node_modules, place it in working frontend directory and restart Next.js server. </p><p>While installing via npm is convenient for developers, it doesnât sound user-friendly. So I decided to go even further and implemented GUI for package managing in the admin panel. When user goes into the theme or plugin market (in the admin panel GUI, same as âAdd new pluginâ in WordPress) and clicks âinstallâ, CMS internally runs yarn command to add a package. Similar happens on remove/uninstall.<br> 22Then every theme can be highly customizable in admin panel drag-and-drop theme editor (sort of a website builder). User can move blocks, change text, images, add plugins, etc. React gives us the power to provide such systems out of the box. </p><img src="/img/blog/1_k-hpw7dtmj590vMZzk4Mag.jpeg"><p>Iâm trying to combine best of the both worlds: properly programmed frontend in React and power in GUI of a normal website builder. Well, Cromwell CMS builder is not yet powerful as well-known solutions, but my goal is to make it so. Important thing is that it follows code-first approach which is the right way in my opinion to build websites. No crippled layouts made from scratch in a glitchy website builder (it actually possible in Cromwell CMS as well, but you wonât do that). 23Anyway, almost everyone when starts with any CMS just picks a ready theme. </p><p>As for developing themes, you can make any Next.js app, just build it with Cromwell CLI that customizes Next.js build process to make your app CMS-compatible. There are also some recommendations like following Next.js static optimization practices, so at run-time Next.js will use <a href="https://vercel.com/docs/concepts/next.js/incremental-static-regeneration" target="_blank" rel="noopener noreferrer">incremental static regeneration</a> making your website work blazingly fast as any other JAM stack website. Technically pre-rendered pages at build time will be re-generated after user installs a theme, but itâs close to JAM stack workflow and itâs available to everyone.</p><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_XX5z" id="plugins"></a>
23Plugins<a class="hash-link" href="#plugins" title="Direct link to heading">#</a></h2><p>Plugins are packages that can export extensions or subscribe to actions (same as hooks in Wordpress). Plugins give you the power to build your app with the best (or at least ones of the best) frameworks there are.<br> 24You can export custom Nest.js controller, TypeGraphQL resolvers, TypeORM entities, and more. Since both REST and GraphQL API are extendable as a plugin author you have a choice to pick whatâs best for your app. 25At the frontend you can register widgets for the admin panel or theme frontend (user will have to place your plugin in theme editor).</p><p>See <a href="https://cromwellcms.com/docs/development/plugin-development/" target="_blank" rel="noopener noreferrer">our guide for more info</a>. 26Plugins can be installed in the admin panel and all extensions will be applied automatically without any manual CLI command. </p><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_XX5z" id="what-your-customers-get"></a>What your customers get<a class="hash-link" href="#what-your-customers-get" title="Direct link to heading">#</a></h2><ul><li>Superfast frontend experience due to the power of React and Next.js statically pre-renders pages.</li><li>Online store and blogging platform. Apart from providing bleeding-edge techs, it must have a decent admin panel experience, not worse than well-known CMS. Modern block-styled text editor based on <a href="https://editorjs.io/" target="_blank" rel="noopener noreferrer">Editor.js</a><img src="/img/blog/1_SKGW9asz4hnAmeWu566mmQ.jpeg"></li><li>Free full-featured online store and blog theme. Free plugins. That and I will be adding more. A user can turn from any other CMS simply and for free start trying or using Cromwell CMS. As for me, itâs a side-project that I really enjoy putting free time into and it wonât change. Everything added for free will stay free forever.<img src="/img/blog/1_eS1P60l8HGt2TwkNUy1PEw.png"></li><li>Easy to install and use themes and plugins. Everything is right in the admin panel GUI. Website builder.</li><li>As concludes from previous points â the tempting ability to exist without web developers.</li><li>SEO friendly. Every page has statically pre-rendered HTML. CMS allows to edit SEO meta-tags, provides automatically generated sitemap and robots.txt.</li><li>Migration. Export your data from other CMS into Excel file and import it.</li><li>Emailing, payments and other integrations.</li></ul><p>In conclusion 27WordPress is often chosen because of its plugins and themes abundance. I cannot replicate it. But I can try to create an environment, what next is up to community. Together we can create a great ecosystem. And more people are using it, more will. Things like that can change the web. 28Iâm not saying that my system is better than WordPress (since I havenât spent a dozen years on it yet), but Iâm trying to solve problems and provide a solution that can be better in a number of ways. 29For now, Iâm asking for feedback on how to improve it. And the project is open-source, anyone can try it. In the end, it all depends on the community. How soon weâll embrace a new most popular language at backend development? Will there be a day when Node.js is powering 78.9% of the internet? ;)</p><p>Originally published in <a href="https://itnext.io/remaking-wordpress-in-js-stack-hello-to-a-new-cms-for-next-js-websites-63096bc5f98b" target="_blank" rel="noopener noreferrer">https://itnext.io/remaking-wordpress-in-js-stack-hello-to-a-new-cms-for-next-js-websites-63096bc5f98b</a> 30<a href="https://app.daily.dev/posts/zyThWPCEq" target="_blank" rel="noopener noreferrer">https://app.daily.dev/posts/zyThWPCEq</a></p></div><footer class="row docusaurus-mt-lg"><div class="col col--9"><b>Tags:</b><ul class="tags_5N4j padding--none margin-left--sm"><li class="tag_LKyA"><a class="tag_JoRF tagRegular_BENv" href="/blog/tags/introduction">Introduction</a></li><li class="tag_LKyA"><a class="tag_JoRF tagRegular_BENv" href="/blog/tags/cromwell">Cromwell</a></li><li class="tag_LKyA"><a class="tag_JoRF tagRegular_BENv" href="/blog/tags/cms">CMS</a></li></ul></div></footer></article><nav class="pagination-nav" aria-label="Blog list page navigation"><div class="pagination-nav__item"></div><div class="pagination-nav__item pagination-nav__item--next"></div></nav></main></div></div></div><footer class="footer footer--dark"><div class="container"><div class="row footer__links">
30<div class="col footer__col"><div class="footer__title">Documentation</div><ul class="footer__items"><li class="footer__item"><a class="footer__link-item" href="/docs/overview/intro">Overview</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/features/overview">Features</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/development/theme-development">Development</a></li><li class="footer__item"><a class="footer__link-item" href="/latest-frontend-dependencies">Frontend dependencies</a></li></ul></div><div class="col footer__col"><div class="footer__title">Community</div><ul class="footer__items"><li class="footer__item"><a href="https://discord.gg/mxmJNSZ2gn" target="_blank" rel="noopener noreferrer" class="footer__link-item"><span>Discord<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_OX1T"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></span></a></li><li class="footer__item"><a href="https://github.com/CromwellCMS/Cromwell/issues" target="_blank" rel="noopener noreferrer" class="footer__link-item"><span>Issues<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_OX1T"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></span></a></li></ul></div><div class="col footer__col"><div class="footer__title">More</div><ul class="footer__items"><li class="footer__item"><a class="footer__link-item" href="/blog">Blog</a></li><li class="footer__item"><a href="https://github.com/CromwellCMS/Cromwell" target="_blank" rel="noopener noreferrer" class="footer__link-item"><span>GitHub<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_OX1T"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></span></a></li><li class="footer__item"><a class="footer__link-item" href="/contacts">Contacts</a></li><li class="footer__item"><a class="footer__link-item" href="/funding">Funding</a></li><li class="footer__item"><a class="footer__link-item" href="/attribution">Attribution</a></li></ul></div></div><div class="logoContainer_yqgz"><div class="logo_JrwJ"></div></div><div class="footer__bottom text--center"><div class="footer__copyright">Copyright © 2022 Cromwell CMS</div></div></div><div>
vendor: 74 bytes, lines 30-31
30 31 <script async src="https://www.googletagmanager.com/gtag/js?id=
31G-W8QY5D61KR
vendor: 22 bytes, lines 31-32
31"></script> 32
32<script>function gtag(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],gtag("js",new Date),gtag("config","G-W8QY5D61KR")</script>
32 33 </div></footer></div>
34<script src="/assets/js/runtime~main.a8162b3a.js"></script>
vendor: 1 bytes, line 34
34
35<script src="/assets/js/main.78c54909.js"></script>
vendor: 1 bytes, line 35
35
36<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"56517f4b0f804e8a814b9550f8963a9a","r":1,"spa":2}' crossorigin="anonymous"></script>
36 37</body> 38</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.