integrate sharp

develop
HerrHase 2 years ago
parent 5c29b92a6e
commit c42119dee5

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

12
package-lock.json generated

@ -8,6 +8,7 @@
"name": "happy-site-webpack-plugin", "name": "happy-site-webpack-plugin",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"crypto": "^1.0.1",
"dayjs": "^1.11.6", "dayjs": "^1.11.6",
"fast-xml-parser": "^4.0.11", "fast-xml-parser": "^4.0.11",
"html-minifier": "^4.0.0", "html-minifier": "^4.0.0",
@ -206,6 +207,12 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/crypto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==",
"deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in."
},
"node_modules/dayjs": { "node_modules/dayjs": {
"version": "1.11.6", "version": "1.11.6",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz",
@ -967,6 +974,11 @@
"resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
"integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==" "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="
}, },
"crypto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig=="
},
"dayjs": { "dayjs": {
"version": "1.11.6", "version": "1.11.6",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz",

@ -6,6 +6,7 @@
"main": "index.js", "main": "index.js",
"description": "Generating a Website from a Markdown Generator", "description": "Generating a Website from a Markdown Generator",
"dependencies": { "dependencies": {
"crypto": "^1.0.1",
"dayjs": "^1.11.6", "dayjs": "^1.11.6",
"fast-xml-parser": "^4.0.11", "fast-xml-parser": "^4.0.11",
"html-minifier": "^4.0.0", "html-minifier": "^4.0.0",

@ -1,15 +0,0 @@
---
title: "Cliche Vegan Messenger"
date_published: "2022-01-10 10:00"
view: "post.njk"
tags:
- tumeric
- heard
- bag
media:
teaser: 'jep.jpg'
meta:
description: "DSA yes plz hot chicken green juice"
robots: "index, follow"
---
## TEST

@ -1,7 +0,0 @@
---
title: "Blog"
view: "blog.njk"
meta:
description: "DSA yes plz hot chicken green juice"
robots: "index, follow"
---

@ -2,7 +2,7 @@
{% block main %} {% block main %}
<img src="{{ page.media.teaser.src | media }}" /> <img src="{{ page.media.teaser.src | resize({ width: 100 }) }}" />
{{ page.content | safe }} {{ page.content | safe }}
{% endblock %} {% endblock %}

@ -0,0 +1,36 @@
/**
*
*
*/
class ConfigStore {
constructor() {
if (!ConfigStore.instance) {
ConfigStore.instance = this;
this._data = {}
}
return ConfigStore.instance;
}
/**
*
*/
set(key, value) {
this._data[key] = value
}
/**
*
*
*/
get(key) {
return this._data[key]
}
}
// create instance
const instance = new ConfigStore();
export default instance

@ -1,7 +1,8 @@
import nunjucks from 'nunjucks' import nunjucks from 'nunjucks'
import { minify } from 'html-minifier' import { minify } from 'html-minifier'
import fs from 'fs'
import { asset, media } from './helpers/engine.js' import { asset, resize } from './helpers/engine.js'
/** /**
* engine - handle eta.js * engine - handle eta.js
@ -18,13 +19,19 @@ class Engine {
// merge options // merge options
this._options = Object.assign({}, { this._options = Object.assign({}, {
autoescapes: true, autoescapes: true,
throwOnUndefined: true throwOnUndefined: true,
web: {
async: true
}
}, options) }, options)
this.nunjucks = nunjucks.configure(views, this._options) this.nunjucks = nunjucks.configure(views, this._options)
this.nunjucks.addFilter('media', function(options) { this.nunjucks.addFilter('resize', (...args) => {
return media(options) const done = args.pop()
}) const options = args?.[2] ? {} : args[2]
resize(args[0], args[1], options, done)
}, true)
// adding defaults for view, function and data from config.yml // adding defaults for view, function and data from config.yml
this._defaults = { this._defaults = {
@ -41,12 +48,11 @@ class Engine {
* @return {string} * @return {string}
* *
*/ */
render(view, data) { render(view, data, done) {
data = Object.assign({}, data, this._defaults) data = Object.assign({}, data, this._defaults)
return minify(this.nunjucks.render(view, data), { this.nunjucks.render(view, data, (error, response) => {
removeComments: true, done(error, response)
collapseWhitespace: true
}) })
} }

@ -8,12 +8,17 @@ import Sitemap from './sitemap.js'
import PagesQuery from './queries/pages.js' import PagesQuery from './queries/pages.js'
import parseYamlFile from './parsers/yaml.js' import parseYamlFile from './parsers/yaml.js'
import configStore from './config.js'
/** /**
* Main
*
*
* *
* @author Björn Hase <me@herr-hase.wtf> * @author Björn Hase <me@herr-hase.wtf>
* @license http://opensource.org/licenses/MIT The MIT License * @license http://opensource.org/licenses/MIT The MIT License
* @link https://gitea.node001.net/HerrHase/happy-site-webpack-plugin.git * @link https://gitea.node001.net/HerrHase/happy-site-webpack-plugin.git
* *
*/ */
class HappySite { class HappySite {
@ -29,6 +34,10 @@ class HappySite {
this._destination = destination this._destination = destination
this._views = views this._views = views
configStore.set('source', source)
configStore.set('destination', destination)
configStore.set('views', views)
// get config for site // get config for site
if (fs.existsSync(this._source + '/site.yml')) { if (fs.existsSync(this._source + '/site.yml')) {
const file = fs.readFileSync(this._source + '/site.yml', 'utf8') const file = fs.readFileSync(this._source + '/site.yml', 'utf8')
@ -37,6 +46,8 @@ class HappySite {
throw new Error('site.yml not found in ' + this._source + '!') throw new Error('site.yml not found in ' + this._source + '!')
} }
configStore.set('site', this._site)
this._engine = new Engine(views, this._site) this._engine = new Engine(views, this._site)
} }
@ -52,14 +63,26 @@ class HappySite {
// run through pages and generate html files // run through pages and generate html files
results.forEach((page) => { results.forEach((page) => {
const content = page.render(this._engine) page.render(this._engine, (error, content) => {
// create directories and write file from page // show errors
mkdirp(this._destination + page.pathname).then(() => { if (error) {
fs.writeFileSync(this._destination + page.pathname + '/' + page.filename, content) console.error(error)
}) }
// if no content show error message
if (!content) {
console.error('Error! Rendering Page ' + '"' + page.filename + '" is null')
return;
}
sitemap.addPage(page) // create directories and write file from page
mkdirp(this._destination + page.pathname).then(() => {
fs.writeFileSync(this._destination + page.pathname + '/' + page.filename, content)
})
sitemap.addPage(page)
})
}) })
// write sitemap // write sitemap

@ -1,8 +1,7 @@
import path from 'path' import path from 'path'
import * as fs from 'fs' import * as fs from 'fs'
import sharp from 'sharp'
const basePath = path.join(path.resolve()) import Media from './../media.js'
/** /**
* asset - checks manifest.json for given path and return * asset - checks manifest.json for given path and return
@ -19,7 +18,7 @@ function asset(staticPath)
let result = staticPath let result = staticPath
// path to mix-manifest // path to mix-manifest
const file = basePath + 'mix-manifest.json' const file = path.join(path.resolve()) + 'mix-manifest.json'
if (fs.existsSync(file)) { if (fs.existsSync(file)) {
@ -43,14 +42,12 @@ function asset(staticPath)
* *
*/ */
function media(src, options) async function resize(src, sizes, options, done)
{ {
console.log(basePath) const media = new Media()
console.log(path.resolve(src))
sharp(src)
.toFile('output.png', (error, info) => { console.log(error) })
return src src = await media.resize(src, sizes, options)
done(null, src)
} }
export { asset, media } export { asset, resize }

@ -0,0 +1,101 @@
import path from 'path'
import * as fs from 'fs'
import sharp from 'sharp'
import mkdirp from 'mkdirp'
import crypto from 'crypto'
import slugify from 'slugify'
import configStore from './config.js'
/**
*
*
*/
class Media {
constructor() {
this._DIR_ASSETS = '/assets/'
}
/**
*
* @param {string} srcPath
* @param {object} sizes
* @param {Object} [options={}]
* @return {string}
*
*/
async resize(src, sizes, options = {}) {
this._extension = path.extname(src)
this._filename = slugify(path.basename(src, this._extension))
this._process = await sharp(configStore.get('source') + '/' + src)
// resize without options and with options
if (Object.getOwnPropertyNames(options).length === 0) {
await this._process
.resize(sizes)
} else {
this._process
.resize(sizes, options)
}
// optimize
this._optimize()
const fileBuffer = await this._process
.toBuffer()
const relativeDestinationPath = this._DIR_ASSETS + this._resolveRelativeDestinationPath(fileBuffer)
// create directories and write file
mkdirp.sync(configStore.get('destination') + relativeDestinationPath)
fs.writeFileSync(configStore.get('destination') + relativeDestinationPath + '/' + this._filename + this._extension, fileBuffer)
return relativeDestinationPath + '/' + this._filename + this._extension
}
/**
* @TODO much nicer to add a hook system so behavior can be change
*
*
* @param {string} extension
*
*/
_optimize() {
if (this._extension === '.gif') {
this._process
.gif({
reoptimise: true
})
} else {
// change extension
this._extension = '.webp'
this._process
.webp({
lossless: true
})
}
}
/**
* resolve path to write file, hash will be get from fileBuffer and
*
*
* @param {object} fileBuffer
* @return {string}
*
*/
_resolveRelativeDestinationPath(fileBuffer) {
const hash = crypto.createHash('sha1')
hash.update(fileBuffer)
return hash.digest('hex').match(new RegExp('.{1,8}', 'g')).join('/')
}
}
export default Media

@ -1,6 +1,7 @@
import path from 'path' import path from 'path'
import slugify from 'slugify' import slugify from 'slugify'
import merge from 'lodash.merge' import merge from 'lodash.merge'
import nunjucks from 'nunjucks'
import parseMarkdownFile from './../parsers/markdown.js' import parseMarkdownFile from './../parsers/markdown.js'
@ -53,7 +54,7 @@ class Page {
* @return {string} * @return {string}
* *
*/ */
render(engine) { render(engine, done) {
const page = Object.assign({}, this._fields) const page = Object.assign({}, this._fields)
@ -61,11 +62,9 @@ class Page {
page.blocks = this._blocks page.blocks = this._blocks
page.path = this.pathname + '/' + this.filename page.path = this.pathname + '/' + this.filename
const result = engine.render(this._fields.view, { return engine.render(this._fields.view, {
page: page page: page
}) }, done)
return result
} }
/** /**

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Loading…
Cancel
Save