Skip to content

v0.4.0 #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.4.0] - Unreleased

## Added
- Build command supports postsFolder (output) argument.
- Input/Output post folder configuration.
- Use hash to write files that have changes only.

## Fixed
- Remove file extension is missing
- Posts subfolder paths were removed during the build process.
- Comments inside file crashed the execution.
- Recent/archive post href uses absolute paths now.

## [0.3.0] - 4-11-2019

## Added
Expand Down
51 changes: 38 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Filler is a tool to create a static website using templates, reusing code and sa
- [x] Uses generic file types only. [v0.1.0]
- [x] Template system. [v0.1.0]
- [x] Snippet system. [v0.1.0]
- [x] Progressive builds (it only builds files that have changed, but you can `--force` it). [v0.1.0]
- [x] Progressive builds (it only writes files that have changed, but you can `--force` it). [v0.1.0]
- [x] CSS minification. [v0.1.0]
- [x] Blog post, recent posts and archive. [v0.1.0]
- [x] Markdown support.
Expand All @@ -43,9 +43,7 @@ Filler is a tool to create a static website using templates, reusing code and sa
- [ ] Example templates.
- [ ] "init" command.
- [ ] Multilingual sites.
- [ ] Webpack support.
- [ ] React support.
- [ ] Server Side Rendering.
- [ ] JS Components (React, Vanilla, Preact...?)
- [ ] SEO features.
- [ ] Any proposal? Contribute!

Expand Down Expand Up @@ -78,6 +76,7 @@ node filler --help
- --force: force build all files. Default: false
- --mode [dev, prod]: build mode. Replace specific snippets. Default: dev
- --recentPosts [number]: number of recent posts rendered. Default: 5
- --postsFodler [string]: output posts folder. Default: blog.

# Documentation

Expand All @@ -87,12 +86,12 @@ Create the following file structure:

```
- ~/Projects/myweb
- /posts -> files can be named freely
- /posts
- post1.html
- /snippets -> supports only two by now: scripts, analytics
- scripts.html -> replaced in all modes
- analytics.html -> replaced only in prod mode
- /templates -> files can be named freely
- /templates
- main.html
- /public -> files and structure can be created freely
- index.html
Expand Down Expand Up @@ -207,12 +206,16 @@ I'm the main web page!!

## Blog system

The files inside the `/post` folder can use any template created inside the `/templates` folder. The idea is to set the parameter `@template <template filename>` inside a comment in the top part of the file. It will also have some extra properties: `@title`, `@description`, `@author` and `@date (dd-mm-yyyyy)`. These properties are used to build the `{{blog:recent-post}}` and `{{blog:archive}}`.
The files inside the `/post` folder can use any template created inside the `/templates` folder. The idea is to set the parameter `@template post` inside a comment in the top part of the file. It will also have some extra properties: `@title`, `@description`, `@author` and `@date (dd-mm-yyyyy)`. These properties are used to build the `post` template itself, the `{{blog:recent-post}}` and `{{blog:archive}}`.

**Note: posts must have the *post* template.**

For exammple:

```
File: ./post/my-first-post.html
<!--
@template main
@template post
@author Some name
@title First post
@date 01-01-2019
Expand All @@ -222,12 +225,30 @@ File: ./post/my-first-post.html
My firs blog post content
```

```
File: ./templates/post.html
<!--
@template main
-->

<div class="post">
<h1>{{title}}</h1>
<div>
<span class="description">{{description}}</span>
</div>
<span class="date">{{author}}, {{date}}</span>
<div>
{{content}}
</div>
</div>
```

If you want to use `{{blog:recent-posts}}` or `{{blog:archive}}`, you need to create the `/template/recentPost.html` or `template/archivePost.html` template in order to render them. For example:

Then you can insert the markups `{{blog:recent-posts}}` or `{{blog:archive}}` where you want, for example in the main page:

```
Result: ./dist/index.html
File: ./public/index.html
<div>
I'm the main web page!!
<h1>Recent posts</h1>
Expand All @@ -249,10 +270,14 @@ Some examples:

```
File: ./template/recentPost.html
<div>
<h1>{{title}} - {{date}}</h1>
<p>{{description}}</p>
<a href="{{href}}">Read more</a>
<div class="post">
<div>
<span class="title">{{title}}</span>
<span class="date">{{date}}</span>
</div>

<span class="description">{{description}}</span>
<a href="{{href}}">Continue reading</a>
</div>
```

Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "filler",
"version": "0.3.0",
"version": "0.4.0",
"main": "./src/index.js",
"scripts": {
"filler": "ts-node ./src/index.ts",
Expand Down
2 changes: 1 addition & 1 deletion src/domain/builder/blog/post.filler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ export const fillPostMetadata = (
.replace("{{author}}", postMetadata.author)
.replace("{{date}}", postMetadata.date)
.replace("{{description}}", postMetadata.description)
.replace("{{href}}", postMetadata.href);
.replace("{{href}}", `/${postMetadata.href}`);
};
3 changes: 2 additions & 1 deletion src/domain/builder/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { IBuilder, IFile, IBuilderCache } from "../../interfaces";
import { buildCss, buildHtml, markdownBuilder } from "./filetype";
import { DirScanner } from "../../lib/dir-scanner";
import { ICache } from "../../lib/cache";
import { getFileMetadata } from "./parser";

export interface IBuilders {
[key: string]: IBuilder;
Expand Down Expand Up @@ -48,7 +49,7 @@ export class Builder {
const posts = this.cache.get("posts").map(
(p: IFile): IFile => ({
...p,
path: config.postsFolder
path: `${config.postsFolder}/${p.path}`
})
);

Expand Down
2 changes: 1 addition & 1 deletion src/domain/builder/filetype/html.builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const buildHtml: IBuilder = async (
});
}

if (file.path === config.postsFolder) {
if (metadata.template && metadata.template === "post") {
const postMetadata = getPostMetadata(config, file);
output = fillPostMetadata(output, postMetadata);
}
Expand Down
7 changes: 0 additions & 7 deletions src/domain/builder/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,6 @@ export function getFileMetadata(file: IFile) {
}

html = fileRaw.substr(endPos);
} else if (
(!startsWithComment && endIndex > -1) ||
(startsWithComment && endIndex === -1)
) {
throw new Error(
`Parser: file ${file.path}/${file.name}.${file.extension} metadata is not correctly formatted.`
);
} else {
html = fileRaw;
}
Expand Down
2 changes: 1 addition & 1 deletion src/domain/loader/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class Loader {

private async loadPosts() {
const config = this.cache.get("config");
const postsFolder = join(config.projectFolder, config.postsFolder);
const postsFolder = join(config.projectFolder, config.inputPostsFolder);
try {
return await DirScanner.scanAndGetFiles(postsFolder);
} catch (error) {
Expand Down
19 changes: 15 additions & 4 deletions src/domain/storer/storer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { IFile, IBuilderCache } from "../../interfaces";
import { DirScanner } from "../../lib/dir-scanner";
import { mkdir, unlink } from "../../lib/io";
import { ICache } from "../../lib/cache";
import { getHash } from "../../lib/hash";

export class Storer {
private cache: ICache<IBuilderCache>;
Expand All @@ -13,6 +14,13 @@ export class Storer {
this.cache = cache;
}

private fileHasChanges(a: IFile, b: IFile) {
const aHash = getHash(a.raw.toString());
const bHash = getHash(b.raw.toString());

return aHash !== bHash;
}

public async saveFile(file: IFile) {
const config = this.cache.get("config");
const outFolder = join(config.distFolder, file.path);
Expand Down Expand Up @@ -45,10 +53,9 @@ export class Storer {
const distFileIndex = distFiles.findIndex(
df => df.name === f.name && df.path === f.path
);

if (
distFileIndex === -1 ||
f.modifiedAt > distFiles[distFileIndex].modifiedAt ||
this.fileHasChanges(f, distFiles[distFileIndex]) ||
config.force
) {
this.saveFile(f);
Expand All @@ -61,14 +68,18 @@ export class Storer {
}

for (const f of distFiles) {
const filePath = join(config.distFolder, f.path, f.name);
const filePath = join(
config.distFolder,
f.path,
`${f.name}.${f.extension}`
);
await unlink(filePath);
console.log(`- ${filePath}`);
filesUpdated += 1;
}

if (filesUpdated === 0) {
console.log("WARNING: There are no changes.");
console.log("There are no changes.");
}
}
}
9 changes: 9 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ buildCmd.addArgument(["--output", "-o"], {
help: "Output folder",
type: "string"
});
buildCmd.addArgument(["--postsFolder"], {
action: "store",
help: "Posts folder",
type: "string"
});

const args = parser.parseArgs();
switch (args.command) {
Expand All @@ -61,6 +66,10 @@ switch (args.command) {
config.recentPosts = args.recentPosts;
}

if (args.postsFolder) {
config.postsFolder = args.postsFolder;
}

build(config);
break;
default:
Expand Down
1 change: 1 addition & 0 deletions src/interfaces/config.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface IConfig {
snippetsFolder: string;
projectFolder: string;
postsFolder: string;
inputPostsFolder: string;
mode: string;
recentPosts: number;
}
14 changes: 14 additions & 0 deletions src/lib/hash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { createHash } from "crypto";

export enum HashAlgorithm {
SHA256 = "sha256"
}

export function getHash(
data: string,
algorithm: HashAlgorithm = HashAlgorithm.SHA256
) {
return createHash(algorithm)
.update(data)
.digest("base64");
}
3 changes: 2 additions & 1 deletion src/use-cases/build/config.default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { IConfig } from "../../interfaces";

export const defaultConfig: IConfig = {
templateFolder: "templates",
postsFolder: "posts",
postsFolder: "blog",
inputPostsFolder: "posts",
publicFolder: "public",
distFolder: "dist",
snippetsFolder: "snippets",
Expand Down
10 changes: 10 additions & 0 deletions test/data/project/posts/2019/subfolder.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!--
@template main
@author Test
@title Subfolder post
@date 03-01-2019
@description Subfolder blog test
-->
<div>
<p>Subfolder</p>
</div>
21 changes: 14 additions & 7 deletions test/unit/builder.html.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ describe("Builder - HTML", () => {
});

test("Recent posts", async () => {
cache.set("config", { ...defaultConfig, recentPosts: 2 });
cache.set("config", { ...defaultConfig, recentPosts: 3 });
cache.set("templates", {
main: {
name: "main",
Expand Down Expand Up @@ -182,10 +182,10 @@ describe("Builder - HTML", () => {
'<!--\n @template main \n--> <div class="recent-posts">{{blog:recent-posts}}</div>'
};

// TODO Check post in subfolder href
const posts = [
'<div href="posts/fourth.html"><p>Fourth post</p><p>Test</p><p>Fourth blog test</p><p>04-01-2019</p></div>',
'<div href="posts/third.html"><p>Third post</p><p>Test</p><p>Third blog test</p><p>03-01-2019</p></div>'
'<div href="/blog/fourth.html"><p>Fourth post</p><p>Test</p><p>Fourth blog test</p><p>04-01-2019</p></div>',
'<div href="/blog/third.html"><p>Third post</p><p>Test</p><p>Third blog test</p><p>03-01-2019</p></div>',
'<div href="/blog/2019/subfolder.html"><p>Subfolder post</p><p>Test</p><p>Subfolder blog test</p><p>03-01-2019</p></div>'
];

const result: IFile = {
Expand Down Expand Up @@ -282,7 +282,7 @@ describe("Builder - HTML", () => {
extension: "html",
path: "",
modifiedAt: new Date(),
raw: "<div>{{title}}</div><p>{{date}}</p>"
raw: '<a href="{{href}}"><div>{{title}}</div><p>{{date}}</p></a>'
}
});
cache.set(
Expand All @@ -298,10 +298,17 @@ describe("Builder - HTML", () => {
raw: "<!--\n @template main \n--> <div>{{blog:archive}}</div>"
};

const posts = [
'<a href="/blog/fourth.html"><div>Fourth post</div><p>04-01-2019</p></a>',
'<a href="/blog/third.html"><div>Third post</div><p>03-01-2019</p></a>',
'<a href="/blog/2019/subfolder.html"><div>Subfolder post</div><p>03-01-2019</p></a>',
'<a href="/blog/second.html"><div>Second post</div><p>02-01-2019</p></a>',
'<a href="/blog/first.html"><div>First post</div><p>01-01-2019</p></a>'
];

const result: IFile = {
...fakeFile,
raw:
"<div> <div><div>Fourth post</div><p>04-01-2019</p><div>Third post</div><p>03-01-2019</p><div>Second post</div><p>02-01-2019</p><div>First post</div><p>01-01-2019</p></div></div>"
raw: `<div> <div>${posts.join("")}</div></div>`
};

const output = await buildHtml(cache, fakeFile);
Expand Down
Loading