Bedrock CLI upgrade

Posted on 21 June 2021 at 18:25 by Wolfr_

Attention to all Bedrock users! Please upgrade your CLI if you wish to keep upgrading Bedrock projects.

 npm install -g bedrock-cli

The new 3.1.0 CLI version adds an option to upgrade Bedrock to the “canary” version, which is one version in front of “development”. To do so, run the following command:

bedrock upgrade --canary

This gives you access to the latest Bedrock release, where we implemented minification of CSS and JS.

We used this release to get rid of some legacy code, which no one should need anymore.

Note: If you are upgrading from an old version of Bedrock (E.g. 1.10-1.17) for some reason, you might want to use the 2.4.0 version of bedrock-cli, but to my knowledge, this would be a super niche use case.

PurgeCSS support in Bedrock 1.34

Posted on 17 June 2021 at 18:34 by Wolfr_

In Bedrock 1.34 we have added the ability to purge your CSS. To enable it, simpy go to bedrock.config.js and set purgeCSS to true.

What does this do? When you run npm run build, Bedrock generates a static site for you. Purge CSS analyzes the output of the HTML, then compares it against the output of the CSS, then removes any classes that you don’t actually use in the HTML in the CSS.

Tailwind heavily depends on this logic, since by default it ships a 4Mb file full of utility classes.

However, this could be useful for any website project. It’s easy to forget a bunch of code. It’s also a lot of work to optimize your dependencies all the time. Why not automate it?

One specific thing to note is that if you use JS to add classes dynamically (as one often does), you can set a special flag for the Purge CSS parser to ignore those classes. See this document.

How to add Tailwind to Bedrock

Posted on 17 June 2021 at 18:01 by Wolfr_

Update June 26: We now have a Tailwind starter branch. Simply run npx degit usebedrock/bedrock#tailwind2 my-bedrock-tailwind-project to get started.

This is available if you use a pre-release of Bedrock 1.34, which is on the development branch.

To try this, grab a fresh Bedrock install:

npx degit usebedrock/bedrock#develop my-bedrock-project

Now, go into the project and the code. First you will want to set your CSS compiler to PostCSS in the bedrock.config.js file:

css: {
  compiler: 'postcss',
    minify: false,
    purge: false
}

The default CSS compiler is scss.

Now, install these dependencies as devDependencies:

npm i -D tailwindcss
npm i -D @tailwindcss/typography

The typography plugin is optional but I like it so I put it here as a default. Add a Tailwind config file:

touch tailwind.config.js

Add contents:

// tailwind.config.js

module.exports = {
  purge: [],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [
    require('@tailwindcss/typography'),
  ],
  separator: '_',
}

Note that the _ separator is needed for Pug. Any Tailwind example you copy paste will need to have the : that is used to for things like hover or dark mode be changed into _ (read docs).

Then change the default postcss.config.js in Bedrock (none found? Check this post) from:

const atImport = require('postcss-import');
const autoprefixer = require('autoprefixer');

module.exports = [atImport, autoprefixer];

To

const atImport = require('postcss-import');
const tailwindcss = require('tailwindcss');
const autoprefixer = require('autoprefixer');

module.exports = [atImport, tailwindcss, autoprefixer];

You can use this mechanism to add any PostCSS plugin you like really. Now test if it works by going to content/postcss/main.css and loading Tailwind by adding these lines:

@tailwind base;
@tailwind components;
@tailwind utilities;

Now you can look at /tmp/main.css (tmp is where files are written to temporarily in dev mode) and be shocked at the 4Mb CSS file.

You will now want to enable CSS purging in the bedrock.config.js. Change

  css: {
    compiler: 'postcss',
    minify: false,
    purge: false
  },

to

  css: {
    compiler: 'postcss',
    minify: false,
    purge: true
  },

Restart bedrock (because you made config changes). Now look at the output again. In the tmp folder you will the same 4Mb CSS file. But if you run npm run build, you will see a much smaller (+-11kb on the default Bedrock install) in the dist folder.

This is because we purge the CSS using the HTML output. This can be used to have a final version of your CSS that has a reasonable file size.

Note that the purge feature is available regardless of using PostCSS. So you can also purge your SCSS output now. As noted in some Github issues, Bedrock might as well be used to make production sites if we can put in just a few more changes (like minifying CSS and JS).

As some may know I am not a big fan of Tailwind, but it has to be said that because of Tailwind I now implemented PostCSS and PurgeCSS support in Bedrock, which I’m sure are good features on their own.

Yeehaw!

1.34 update notice

Posted on 17 June 2021 at 17:52 by Wolfr_

This is a notice for the upcoming 1.34 release which provides support for using PostCSS as well as PurgeCSS.

If you want to make use of the new PostCSS feature, you will need to add a file called postcss.config.js to the root of your project with following contents:

const atImport = require('postcss-import');
const autoprefixer = require('autoprefixer');

module.exports = [atImport, autoprefixer];

This manual update is needed because the upgrade mechanism from bedrock-cli only upgrades the core folder.

If you update an old project it is also wortwhile to copy/paste the new dependencies, because that also doesn’t get updated automatically. Truth be told, we could do better in terms of upgradeability. If you are stuck with anything, please file a Github issue and we can try to help.

Implementing multi-language prototypes in Bedrock

Posted on 17 June 2021 at 11:34 by Wolfr_

For a recent prototype, the requirement was that we would work in multiple languages. In the case of this project Dutch and English.

Now that things are still fresh, I’m doing this writeup so that I know what to do next time. And maybe this will help some people? Blogging is how I remember 😉

So first of all you will want to make two folders in content/templates with the shortcodes for your languages. So in this case a nl and and en folder.

Choose one of your languages to be the main language. Now, create files that match the URL structure on both sides. So let’s say you have an about.pug in en you will have an over-ons.pug in the nl part.

Here’s how that would look in a tree structure:

.
|-- en
|   `-- about.pug
`-- nl
    `-- over-ons.pug

Now use template extension to extend the template in the non-main language*. So let’s say that nl is the main language we are developing in. Then, don’t repeat the full template in the en version.

Instead use extends /templates/nl/over-ons in en/about.pug ; and literally only that. The file is needed to create the URL. The extension makes sure the content is exactly the same.

Then, in the “Over ons” template you can then localize content. To make sure you can localize content at all you will need translation strings. Make a new file in data called content-strings.js. In this file, create a structure as follows:

'use strict';

let contentStrings = [
  {
    "readMore": "Lees meer",
    "chooseLanguage": "Kies taal"
  },
  {
    "readMore": "Read more",
    "chooseLanguage": "Choose language"
  },
];

module.exports = contentStrings;

Now you can call this structure in your template:

#{contentData.contentStrings[0].readMore}

This syntax is no fun; and also, we are not showing the right language in the en part of the site.

Let’s provide a helper function to be able to correctly show the right string in the right language in master.pug . Add this code to the pageVariables block:

- var activeLangIndex = null
- var lang = pathname.split("/")[0];
-
    if (lang == "nl") { activeLangIndex = 0 }
    if (lang == "en") { activeLangIndex = 1 }
- var t = contentData.contentStrings[activeLangIndex]

What are we doing here? We are associating the active language with the first part of the URL, and pointing to a lil variable called t (for translation, get it?) to be a helper.

Now we can simply write:

#{t.readMore}

And lo an behold, on the nl part it will show up as Lees meer and on the en part it will show up as Read more.

So this is the basic gist of how you would implement multiple languages using the powerful Pug templating language together with Bedrock’s content data feature.


*I realize this can get tedious. Bedrock is meant as a prototyping environment and not to create production sites. In our project, we translate a few parts of the prototype to a different language, but in production a CMS or a JS framework with a more full-fledged i8n solution is swapped in. However, some recent changes to Bedrock made me wonder if we shouldn’t just go ahead and try to make Bedrock output ready for production. We are close to having all the features you need for simple websites.

Perhaps if you really want to go to production you can script the generation of the en structure using a helper script. But for small sites it is probably faster to just do the manual work.

Bedrock 1.32.0 notice

Posted on 8 June 2021 at 15:22 by Wolfr_

Attention! There is now a difference how Javascript gets transpiled in the latest Bedrock version.

It used to be that everything would get put into a big bundle.js.

Now we are separating out the bundle of the code needed to run Bedrock and the code of the prototype itself. They are in 2 files now called bundle-prototype.js and bundle-client.js.

This way, external developers receiving the prototype have an easier time integrating, and we can also potentially change the way these get transpiled separately through a setting in the future.

How to upgrade? There is some manual work involved.

  • Run bedrock upgrade --dev  in the root folder (make sure you have the Bedrock CLI installed https://github.com/usebedrock/bedrock-cli )
  • To upgrade old prototypes, you need to change the reference to bundle.js in master.pug to
script(src='/js/bundle-client.js')
script(src='/js/bundle-prototype.js')
  • Then, remove this line in content/index.jsimport "../../core/js/index";

Feedback & issues welcome.

Update June 9: We’ve added better docs.

New experimental feature: work with a linked npm package

Posted on 26 April 2021 at 11:55 by Wolfr_

A new feature is in the works, to work with a linked npm package and still maintain live reloading when making a change.

This blog post is the documentation for that feature.

For the purposes of this example, we will use the imaginary project method. Let’s say you decide to put the CSS in an NPM package, and the CSS uses SCSS. You want to work on your prototype, but you also want to work directly in the CSS package.

In order to do this, you would open two separate projects in your text editor: one for the CSS and one for the main project.

Now, a workflow problem occurs: a file save in the package folder (contained in node_modules) will not trigger a change in your prototype. You’ll have to make a new version and re-publish it, and then npm install to see the changes. Of course this is not how you want to develop. You can put the styles locally, but then you lose the context of the package. So what do you do? npm link to the rescue. npm link allows you to link a local package and use it while developing.

Make sure you have a checked out version of method-css (your CSS package repo) and a checked out version of method-prototype (your Bedrock repo).

In bedrock.config.js add the option:

compileNodeModuleCSS: 'method-css',

For this to work, we are assuming an *.scss file lives in the root of the package. Technically you can have more than one SCSS file, but this is untested.

Install the package in method-prototype:

npm i method-css

Go to ~/Sites/method-css (or wherever your local project lives) and run npm link

Then go to ~/Sites/method-prototype (or wherever your local project lives) and run npm link method-css.

Make sure the package is referenced in main.scss:

@import "../../node_modules/method-css/main.scss";

Now, if you make a change to the package, it should reflect in the Bedrock prototype, with the live reload working.

P.S. The code for this feature is not yet public, but will land in a next Bedrock version.

P.P.S. June 17, 2021: We decided to not ship this feature for now.

Bedrock 1.28.1

Posted on 8 March 2021 at 20:34 by Wolfr_

New release! Or actually 2 new point releases. I never really know what a “feature” and a “bugfix” is in the case of Bedrock. In any case, here are some improvements:

Peace out!

Bedrock 2: an update

Posted on 31 January 2021 at 18:03 by Wolfr_

In September ’19, I blogged about Bedrock 2 for the first time. The idea has now evolved to an implementation in Ember, Angular, Svelte and Vue. In this blog post I will give a global summary.

Around five years ago — yes, really! It’s that long ago — we released Bedrock to the world as an open source project. Bedrock is a tool to help with prototyping user interfaces using HTML and CSS.

We made this very documentation website you are visiting right now, and we learned a lot improving upon it & maintaining it over the years.

While Bedrock is completely open source, most usage was as an internal tool at Mono and as far as I know did not get much usage outside of our company. At some level this is fine, because it was doing it’s job for us and maintaining OSS can be a pain. At another level I would have liked more companies to use it to grow it as a project.

Over the years, a problem crept up on us: the dev world had moved to using Javascript frameworks for their front-ends. Simply delivering static HTML/CSS wasn’t good enough anymore in some cases.

I started toying around with porting the features of Bedrock to environments powered by the popular JS frameworks.

In Aprl last year I wrote the idea of Bedrock 2 down in a design document, which outlined a vision for what Bedrock 2 is. The main idea is to build on top of existing frameworks to deliver the functionality of Bedrock.

Up until today, we’ve released some early versions of Bedrock2:

These are all early example implementations. Some of these already have improved version, but we didn’t get to open sourcing them yet. These better versions currently live in client projects.

Whichever one of these evolves depends on what type of design projects we are working on at Mono. I am curious which one evolves the most over the coming year 😉 (I wish more clients would ask for Vue projects, because I like that one the best.)

While testing these in real-world projects, we’ve also learned that Bedrock 1 is still a viable tool. It has some features like page states and reliable static deployment that make it the go-to tool for some types projects.

For example, in large prototypes with lots of user roles, where the different user roles see a different UI, Bedrock 1 is immensely helpful. The features to simulate the UI states don’t exist in none of the Bedrock 2 versions.