Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/tsertkov/m9-generator
m9 - Static Site Generator
https://github.com/tsertkov/m9-generator
Last synced: 23 days ago
JSON representation
m9 - Static Site Generator
- Host: GitHub
- URL: https://github.com/tsertkov/m9-generator
- Owner: tsertkov
- License: mit
- Created: 2017-11-17T23:02:47.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2020-04-27T11:37:12.000Z (over 4 years ago)
- Last Synced: 2024-10-08T22:38:41.800Z (about 1 month ago)
- Language: JavaScript
- Homepage:
- Size: 1.39 MB
- Stars: 5
- Watchers: 2
- Forks: 1
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# m9-generator
> Static site generator powered by `webpack` bundling, `handlebars` templating and `browser-sync` live-reloading.
## Table of Contents
* [Overview](#overview)
* [Installation](#installation)
+ [Yarn tasks as package.json scripts](#yarn-tasks-as-packagejson-scripts)
* [CLI interface](#cli-interface)
* [API interface](#api-interface)
* [Development mode](#development-mode)
* [Source and Destination directories](#source-and-destination-directories)
* [Stages](#stages)
* [Entrypoint files](#entrypoint-files)
* [Target browsers](#target-browsers)
* [Babel](#babel)
* [Handlebars](#handlebars)
+ [Partials](#partials)
+ [Layouts](#layouts)
+ [Helpers](#helpers)
+ [Embedded handlebars-helpers](#embedded-handlebars-helpers)
* [Webpack](#webpack)
+ [Development and Production modes](#development-and-production-modes)
+ [Handlebars loader](#handlebars-loader)
+ [Babel loader](#babel-loader)
+ [PostCSS loader](#postcss-loader)
+ [Visualizer](#visualizer)
* [Metalsmith](#metalsmith)
+ [Configuration](#configuration)
+ [Front-matter](#front-matter)
+ [Handlebars template data context](#handlebars-template-data-context)
- [System data](#system-data)
- [Static content](#static-content)
- [Dynamic content](#dynamic-content)
+ [Public directory](#public-directory)
* [Developing m9-generator](#developing-m9-generator)## Overview
m9-generator is static site generator relying on `handlebars` for static files templating, `webpack` for JavaScript and CSS bundling and `browser-sync` for local live-reload development server.
m9-generator follows future-focused approach and provides support to new standard solutions when handling CSS and JavaScript.
- JavaScript: [Stage3](https://babeljs.io/docs/en/babel-preset-stage-3)
- CSS: [Stage2, nesting-rules, custom-media-queries](https://preset-env.cssdb.org/features)## Installation
> NB! Use `yarn` instead of `npm`. m9-generator depends on `peerDependencies` in `package.json` and so far only `yarn` installs them.
> NB! It is assumed that per-site directory layout with package.json is used in this documentation examples. Use `yarn init` to create one.
Install `@tsertkov/m9-generator` as your local depencency:
```sh
$ yarn add @tsertkov/m9-generator
```### Yarn tasks as package.json scripts
Add following `scripts` in your site `package.json`:
```json
"scripts": {
"m9": "m9",
"test": "m9 test",
"dev": "m9 dev",
"build": "m9 build"
}
```To run m9-generator tasks with `yarn` locally
```sh
$ yarn test
$ yarn run dev
$ yarn run build
$ yarn run m9
$ yarn run m9
```## CLI interface
m9-generator comes with `m9` command line tool to execute `gulp` tasks.
Run `yarn run m9` to execute default help task printing complete list of available tasks to run with `yarn run m9 `.
There are tasks and sub-tasks in m9-generator. Tasks are always a groups of sub-tasks.
Main tasks are:
- `build`: build static site files into destination directory
- `dev`: continuously build and live-reload site with local development server
- `test`: test siteRun `./node_modules/.bin/m9` to see default help screen:
```
Main Tasks
------------------------------
build
dev
help
testSub Tasks
------------------------------
build-clean
build-copy
build-metalsmith
build-webpack
dev-browsersync
dev-watch
test-standard
```Run `./node_modules/.bin/m9 --tasks` to see complete task tree generated by `gulp`.
```
[13:23:38] ├── build-clean
[13:23:38] ├── build-copy
[13:23:38] ├── build-metalsmith
[13:23:38] ├── build-webpack
[13:23:38] ├── dev-browsersync
[13:23:38] ├── dev-watch
[13:23:38] ├── help
[13:23:38] ├── test-standard
[13:23:38] ├─┬ build
[13:23:38] │ └─┬
[13:23:38] │ ├── build-clean
[13:23:38] │ ├── build-copy
[13:23:38] │ ├── build-webpack
[13:23:38] │ └── build-metalsmith
[13:23:38] ├─┬ dev
[13:23:38] │ └─┬
[13:23:38] │ ├── build-clean
[13:23:38] │ ├── build-copy
[13:23:38] │ ├── dev-browsersync
[13:23:38] │ ├── build-metalsmith
[13:23:38] │ └── dev-watch
[13:23:38] ├─┬ test
[13:23:38] │ └─┬
[13:23:38] │ └── test-standard
[13:23:38] └─┬ default
[13:23:38] └─┬
[13:23:38] └── help
```## API interface
m9-generator exports preconfigured `gulp` instance. See [gulp API docs](https://github.com/gulpjs/gulp/blob/master/docs/API.md) for details.
Example using m9-generator API:
```javascript
const m9 = require('@tsertkov/m9-generator')()
m9.series('build')(err => {
if (err) {
console.log('error happened', err)
} else {
console.log('build done')
}
})
```## Development mode
`yarn run dev` executes BrowserSync serving static files from build directory connected to webpack-dev-middleware for dynamic asset serving.
Look for BrowserSync details in output:
```
[Browsersync] Access URLs:
--------------------------------------
Local: https://localhost:3000
External: https://192.168.0.1:3000
--------------------------------------
UI: http://localhost:3001
UI External: http://192.168.0.1:3001
--------------------------------------
[Browsersync] Serving files from: /Users/example/Projects/example.com/build
```Updates to most of the `src/**/*` files must trigger recompilation and live-reload updated pages opened in browsers.
Run `yarn run test` to execute automated tests for current site.
## Source and Destination directories
`m9` works by reading input from files in source directory, builds site, then persists files in destination directory. By default source and destination directories are `./src` and `./build` accordingly.
Directories can be set with command line argument `--src=`, `--dst=` or environment variable `SRC` and `DST`.
## Stages
Stage defaults to `development` and defines environment current site is building for.
Stage can be set with command line argument `--stage` or `STAGE` environment variable:
- `STAGE=staging yarn run build`
- `yarn run build --stage=staging`## Entrypoint files
m9-generator uses `metalsmith` to build static files and `webpack` to bundle JavaScript and CSS. Both are relying on entrypoint files as their input.
Each file matched by `/pages/**/*.hbs` pattern is processed by `metalsmith` resulting in one or many files build in destination directory. All other files in `/pages/**/*` are copied as is.
Each file matched by `/scripts/*.js|.css` pattern is bundled in corresponding JS or CSS file in `/assets` directory.
## Target browsers
Webpack loaders for JavaScript and CSS are respecting configured target browsers defined in [`.browserslistrc`](https://www.npmjs.com/package/browserslist) file.
> NB! The most pragmatic browserlist query is used by default when `.browserslistrc` file is not given.
## Babel
Two different babel transformation processes are running in m9-generator. One is done by `@babel/register` transpiling files on the fly for current node version using require hook. Another by webpack bundling client-side package with `babel-loader`.
Both transformations use the same presets `@babel/preset-stage-3` and `@babel/preset-env`, but differ in targets for `preset-env`.
## Handlebars
Handlebars is simple, powerful and extendable templating system. Custom Partials and Helpers allow building reusable components with ease. Read more on https://handlebarsjs.com/.
### Partials
By default handlebars partials are loaded from `/partials/*.hbs`. Read more about handlebars partials on https://handlebarsjs.com/partials.html.
### Layouts
Layouts are implemented by native handlebars [partial blocks](https://handlebarsjs.com/partials.html#partial-block).
Layout example `/partials/layout-default.hbs`:
```handlebars
{{title}}
{{> header}}
{{> @partial-block}}
{{> footer}}
```
Page template example `/pages/index.html.hbs`:
```handlebars
---
title = "{{site.title}}"
---
{{#> layout-default}}
{{{readme.content}}}
{{/layout-default}}
```### Helpers
Helpers are loaded with `/helpers/*.js` pattern.
These are native JavaScript files and must use `module.exports = (content) => 'output string'` format to enable dynamic loading.
### Embedded handlebars-helpers
188 helpers from [`handlebars-helpers`](https://github.com/helpers/handlebars-helpers) are available to handlebars engine. Before writing your own first consider searching similar in [handlebars-helpers](https://github.com/helpers/handlebars-helpers).
## Webpack
Webpack searches for entry points in `/scripts/*.js` and `/styles/*.css` and writes files in `/assets/`.
There is `/assets/manifest.json` file with assets manifest pre-loaded into templating context as `__assets` variable.
### Development and Production modes
`development` mode is enabled when `stage === 'development'` is true. Otherwise `production` mode is active. Different optimizations and loader settings are enabled based on active mode.
### Handlebars loader
`*.hbs` files are converted to compiled handlebars template functions including resolved helpers, partials and runtime automatically.
```JavaScript
import itemCard from '../../partials/item-card.hbs'// ..
const item = { key: "value" }
const html = itemCard(item)
// ..```
Read more about `handlebars-loader` at https://github.com/pcardune/handlebars-loader#readme.
### Babel loader
`*.js` files are processed by babel using browsers target defined in `.browserslistrc` or default one for browsers.
Ream more about `babel-loader` at https://github.com/babel/babel-loader#readme.
### PostCSS loader
`*.css` files are processed by PostCSS with `postcss-preset-env`.
Read more about `postcss-loader` at https://github.com/postcss/postcss-loader#readme.
### Visualizer
In `development` mode [webpack-visualizer-plugin](https://github.com/chrisbateman/webpack-visualizer#readme) is enabled and results are avalable at `https://localhost:3000/webpack-visualizer/` or other domain/port you use locally.
## Metalsmith
Metalsmith compiles static files found in `/pages/` into `/` directory. It extracts front-matter headers and passes `*.hbs` files through Handlebars templating system.
### Configuration
m9-generator builds single configuration object internally. This object can be modified per site by exporting configuration function in `/config.js`.
Stage aware configuration file example:
```JavaScript
const config = {
default: {
apiEndpoint: 'https://staging-api.example.com'
},
development: {
site_url: 'https://localhost:3000'
},
staging: {
site_url: 'https://staging.example.com'
},
production: {
site_url: 'https://example.com',
apiEndpoint: 'https://api.example.com'
}
}module.exports = m9config => Object.assign(
m9config,
Object.assign(
{},
config.default,
config[m9config.stage]
)
)
```### Front-matter
Metalsmith is parsing front-matter headers in template files using `---` as delimiter. Front-matter content must be in TOML format. It is used to control metalsmith plugins and overwrite data context variables.
### Data context
m9-generator preloads data context and exponses it to Handlebars templating. There are two types of input data: **static content** in form of json files and **dynamic content** as JavaScript files.
#### System data
System variables avaialble in template context are prefixed with `__`.
| Variable name | Description |
| --- | --- |
| `__assets` | Webpack assets manifest: `asset-name -> asset-filename` |
| `__config` | Configuration object |#### Static content by `json-dir` content plugin
Static content is loaded from JSON files found in `/content/static` directory.
For example following static content files in `content/static` directory:
```javascript
// content/static/user.json
{
[
"name": "user1",
"email": "[email protected]",
"group": [{
"ID": 1
}
],
[
"name": "user2",
"email": "[email protected]",
"group": [{
"ID": 2
}
]
}// content/static/group.json
{
[
"id": 1,
"name": "group1"
],
[
"id": 2,
"name": "group2"
]
}// content/static/site.json
{
"adminEmail": "[email protected]",
"title": "site title",
"description": "site description"
}
```This content is accessible in handlebars templates as variables: `user`, `group` and `site` accordingly to JSON file names.
```handlebars
site title: {{site.title}}
name property of first user in collection: {{user.[0].name}}
name property of first group in collection: {{group.[0].name}}
first user group name: {{user.[0].group.[0].name}}
second user group name: {{user.[1].group.[0].name}}
```#### Dynamic content by `js-dir` content plugin
It is possible to define dynamic (programmable) content and expose it to template data. Each JavaScript file in `/content/dynamic` must follow pattern `.js` and export function of a form:
```javascript
module.exports = function (proto, content, config) {
// do something with the proto (it is actual entity obj in fact)
Object.defineProperty(proto, 'content', {
configurable: true,
enumerable: true,
get: () => {
// return smth
return 'empty value'
}
})return proto
}
```Augmenting initial content loaded from static JSON files with dynamic functions is a common integration method. In cases when static content of the same content type is not found new empty object is passed as `proto` to a content function.
### Public directory
All files and folders from `/public/` directory are copied to destination `` directory. This is a good place to put static image files, favicons, etc.
## Custom gulp tasks
Gulp tasks found matching `/tasks/*.js` are automatically registrered and available via m9 cli.
For example `/tasks/custom-task.js` to define `custom-task`:
```javascript
module.exports = async function customTask (config) {
console.log('Custom task test')
}
```## Developing m9-generator
### JavaScript transpilation
JavaScript sources of m9-generator are transpiled with babel. Sources are located in `src/` directory. Compiled files are placed in `dist/`.
Run `npm run build-dist` to compile files in `dist/`.
By default m9 runs from `dist/` directory. To run from `src/` during development pass `--m9-use-src` command line argument.
### Embedded documentation site
Documentation site is embedded with m9-generator. Its source directory is `docs-src/` and destination `docs/`.
Run `npm run dev` to start development server for documentation site.
### Using `npm link`
Run `npm link` inside m9-generator local repo to link it from global node_modules. To link dev version of m9-generator in site project run `npm link @tsertkov/m9-generator`.
For example assume having `~/m9-generator` and `~/my-example-site` with generator repo and site repo accordingly. Then to run example-site using m9-generator from `~/m9-generator` do the following:
```sh
$ cd ~/m9-generator
$ npm link
$ cd ~/my-example-site
$ npm link @tsertkov/m9-generator
$ npm run dev --m9-use-src
```### Publish new npm version
Use `npm version` command to publish new version of npm package and push new git tag to remote.