hamlet-builder
v1.5.1
Published
Compiler used by the Hamlet theme for Blogger developers.
Readme
Hamlet-builder
This package makes it easy to build a Blogger Template. It is used to build the Blogger template Hamlet, and all Blogger themes derived from it.
Features
- Use Handlebars to compile HBS and XML files
- Use Rollup to bundle JS files
- Use PostCSS to process CSS files
- Minify CSS and JS files using LightningCSS and Terser (Can be disabled)
- You can use the Blogger language with some additional facilities
- You can use configuration files to customize the build process (Optional)
- Fast and easy to use
Install
npm install hamlet-builderFlags
| Flag | Short Flag | Description | Default |
| ----------------- | ---------- | ----------------------------------- | ------- |
| --input | -i | Input path | src |
| --output | -o | Output path | dist |
| --mode | -m | Set mode: development or production | development |
| --watch | -w | Watches the source files and rebuilds on changes | |
| --info | -I | Display information about the project | |
| --no-minify | -n | Disable all minification | |
| --no-minify-css | | Disable minification for CSS | |
| --no-minify-js | | Disable minification for JS | |
Usage
Add some scripts to your package.json, a good way to do it is the following:
{
"scripts": {
"dev": "hamlet --mode development --watch",
"start": "hamlet --mode production --watch",
"build": "hamlet --mode production"
}
}[!NOTE] You can invoke the CLI using either
hamletorhamlet-builder.
Then you can run the following commands:
npm run start
npm run buildYou can also use the CLI directly. For example, to start it in development mode with automatic file watching:
npx hamlet --mode development --watchConfiguration Files
Hamlet
Configuration file for Hamlet plugins, custom helpers, and build options. You can add a configuration file to the root of your project by creating a .hamletrc.js or hamlet.config.js file, or by placing a hamletrc.js file inside a .config/ folder. You can also use .cjs or .mjs extensions.
Basic configuration
import testPlugin from '@hamlet/test-plugin'
export default {
recompileStyleOnAnyChange: false,
helpers: {
sayHello: name => `Hello, ${name}!`,
},
plugins: [
testPlugin(),
]
}Options
helpers— Object with custom Handlebars helpers. These helpers don't require namespacing and can override built-in helpers if needed. Use for local project helpers only; for distributable helpers, use thepluginssystem with namespacing.plugins— Array of plugin factory functions. Each plugin should return an object withpartialsand/orhelperskeys. Namespaced helpers/partials from plugins cannot override built-in or previously registered ones (will be skipped with a warning).recompileStyleOnAnyChange— Boolean (default:false). Iftrue, CSS is recompiled whenever any file changes (useful for class-based CSS frameworks like Tailwind that generate styles dynamically).
Using context in configuration
If your configuration needs access to paths or other context information, export a function instead of an object:
export default ({ paths }) => ({
recompileStyleOnAnyChange: true,
helpers: {
projectRoot: () => paths.root,
},
plugins: [
// can use paths.src, paths.dist, etc.
]
})Available context properties:
paths.root— Absolute path to the project rootpaths.src— Absolute path to the source directory (input)paths.dist— Absolute path to the output directory (dist)
Plugin development
A plugin must export a default function that returns an object with partials and/or helpers. If a plugin tries to register a name that already exists (a built-in helper/partial, or one from another plugin), it will be skipped with a console warning instead of overwriting it.
[!IMPORTANT] Plugins execute arbitrary Node.js code. Treat them as you would any other npm dependency—only install plugins from trusted sources.
[!TIP] Want to build your own plugin? Check out the official starter: hamlet-plugin-template.
Rollup
Add a .rolluprc.js, rollup.config.js or create a folder .config with a file rolluprc.js. You can also use the extension .cjs or .mjs. Here is an example of configuration:
import terser from '@rollup/plugin-terser'
export default {
plugins: [
terser()
]
}[!NOTE] The
babelplugins are used by default if a configuration file is not specified.
PostCSS
Add a .postcssrc.js, postcss.config.js or create a folder .config with a file postcssrc.js. You can also use the extension .cjs or .mjs. Here is an example of configuration:
import autoprefixer from 'autoprefixer'
import cssnanoPlugin from 'cssnano'
export default {
plugins: [
autoprefixer(),
cssnanoPlugin()
]
}[!NOTE] The
autoprefixerplugin is used by default if a configuration file is not specified.
Theme
Add a .themerc, .themerc.json, theme.config.json or create a folder .config with a file themerc.json. Also you can add the information in the package.json file using the theme key. Here is an example of configuration:
{
"theme": {
"name": "Hamlet",
"author": "zkreations"
}
}The data will be the context of the Handlebars templates, so you can access them as follows:
{{name}}
{{author}}Browserlist
Add a .browserslistrc or add the information in the package.json file using the browserslist key. Here is an example of configuration:
{
"browserslist": [
"last 2 versions",
"not dead"
]
}More information about the Browserslist configuration, check the Browserslist repository.
Structure
The user is free to organize the files and folders as they wish, as the system will search for scss, sass, css, js, hbs and xml files to compile them as needed.
Compile styles
The system will search for sass, scss and css files to compile them. If the file name starts with an underscore _, it will be considered a partial file, for example:
├── src
│ ├── scss
│ │ ├── _module.scss
│ │ └── main.scssAnother example with css files:
├── src
│ ├── css
│ │ ├── _module.css
│ │ └── main.cssThe file main.scss or main.css will be the main file that will be compiled and saved in the default output folder or the one specified by the user.
[!TIP] The PostCSS plugins will also be applied to the
sassandscssfiles after being compiled.
Compile scripts
The system will search for js files, however only those that end with bundle.js will be considered as main files, for example:
├── src
│ ├── js
│ │ ├── module.js
│ │ └── main.bundle.jsThe file main.bundle.js will be the main file, while the other files will be considered as modules. Also, when the main file is compiled, "bundle" is removed from the file name, so the resulting file will be main.js.
[!NOTE] The name of the main file will be used as the name of the function generated by Rollup.
Compile templates
The system will search for xml, hbs and handlebars files to compile them. If the file name starts with an underscore _, it will be considered a partial file, for example:
├── src
│ ├── templates
│ │ ├── _module.hbs
│ │ └── main.hbsAnother example with xml files:
├── src
│ ├── templates
│ │ ├── _module.xml
│ │ └── main.xmlThe file main.hbs or main.xml will be the main file that will be compiled and saved in the default output folder or the one specified by the user.
You can create any number of partials and organize them as you wish, just make sure to use unique names, when a partial is repeated you will receive a warning message. To include a partial use the following syntax:
{{> module}}[!TIP] If you have a folder with partials that you frequently create or delete, and they are also called together in a main file, you can use the
folder.prefix to include all the partials from that folder, for example:{{> folder.FOLDER_NAME}}
Helpers
These helpers are defined by default in the system, and you can use them in your templates. You can add custom helpers in your hamlet.config.js:
export default {
helpers: {
myHelper: value => value.toUpperCase(),
}
}Built-in helpers available:
| Helper | Description |
| ------ | ----------- |
| asset | Include the content of the file in the template |
| currentYear | Include the current year |
| eq | Check if two values are equal (===) |
| ne | Check if two values are not equal (!==) |
| lt | Check if the first value is less than the second |
| gt | Check if the first value is greater than the second |
| and | Logical AND between two values |
| or | Logical OR between two values |
| not | Negate a value |
| concat | Concatenate multiple strings |
| includes | Check if a string contains a substring |
| capitalize | Capitalize the first letter of a string |
| first | Get the first element of an array |
| last | Get the last element of an array |
| switch / case / default | Block helpers to create switch-like conditional logic |
Example of use the asset helper:
{{asset "dist/css/main.css"}}
{{asset "dist/js/main.js"}}If the file is in the node_modules folder, you can omit the folder and use ~ to reference it:
{{asset "~/tooltips/main.css"}}[!IMPORTANT] Remember to use the
<style>and<script>tags to include the CSS and JS files in your template.
Example of use the currentYear helper:
{{currentYear}}Example of use the comparison and logic helpers:
{{#if (eq view.type "post")}}
This is a post
{{/if}}
{{#if (and isPost hasThumbnail)}}
This post has a thumbnail
{{/if}}Example of use the switch / case / default helpers:
{{#switch view.type}}
{{#case "post"}}This is a post{{/case}}
{{#case "page"}}This is a page{{/case}}
{{#default}}Unknown type{{/default}}
{{/switch}}Partials
There are predefined partials that you can use in your templates. These are identified with the prefix hamlet.. To learn more, you can refer to the documentation on default partials. Below is a table with the available partials:
| Partial | Description |
| ------- | ----------- |
| hamlet.defaultmarkups | Clean and include the default widgets of Blogger |
| hamlet.ads | Function: Create adsense ads |
| hamlet.adsense | Function: AdSense async script |
| hamlet.attr | Function: Add or remove multiple attributes |
| hamlet.avatar | Function: Replace the default avatar image with a custom image |
| hamlet.image | Function: Create custom image tag |
| hamlet.kind | Function: add classes to body tag based on the current view |
| hamlet.menu | Function: Create a menu from a list of links |
| hamlet.meta | Function: Generate meta tags |
| hamlet.picture | Function: Create custom picture tag |
| hamlet.snippet | Function: Create a snippet of a string |
| hamlet.skinVars | Function: Generate CSS variables from the skin data |
| hamlet.functions | Include all functions partials |
Additional features
When writing your templates, you will be able to use the Blogger language you already know, with some additional facilities.
Root
You don't need to add the attributes to the root tag:
<html class='test'>The above will compile to:
<html class='test' b:css='false' b:js='false' b:defaultwidgetversion='2' b:layoutsVersion='3' expr:dir='data:blog.languageDirection' expr:lang='data:blog.locale'>Variables
You can define variables with only the name attribute:
<Variable name="test"/>
<Variable name="example" value="false"/>The above will compile to:
<Variable name='test' description='test' type='string'/>
<Variable name='example' description='example' type='string' value='false'/>Widgets
In the case of the widget tags, no attribute is required, you only need the type:
<b:widget/>
<b:widget type='PopularPosts'/>
<b:widget type='Label'/>
<b:widget type='Label'/>The above will compile to:
<b:widget id='HTML1' type='HTML' version='2'/>
<b:widget id='PopularPosts1' type='PopularPosts' version='2'/>
<b:widget id='Label1' type='Label' version='2'/>
<b:widget id='Label2' type='Label' version='2'/>[!NOTE] When
typeis not specified, or if the specified type is not valid,HTMLwill be used by default.
Normalize spaces
When you use b:* tags you can use spaces or line breaks to improve the clarity of your code, when it is compiled, these spaces will be normalized.
<b:include name='@image' data='{
src: data:sourceUrl,
resize: (data:shrinkToFit
? 500
: 1280)
}'/>The above will compile to:
<b:include name='@image' data='{ src: data:sourceUrl, resize: (data:shrinkToFit ? 500 : 1280) }'/>Create your beautiful theme
If you used this repository as a template, please, add a star ⭐ and add the following tags in yours:
blogger-hamletblogger-handlebarsblogger-hbs
Thanks for using this repository. Happy coding! 🐋
Supporting
If you want to help me keep this and more related projects always up to date, you can buy me a coffee ☕. I will be very grateful 👏.
License
Hamlet-builder is licensed under the MIT License
