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",
"version": "0.1.0",
"dependencies": {
"crypto": "^1.0.1",
"dayjs": "^1.11.6",
"fast-xml-parser": "^4.0.11",
"html-minifier": "^4.0.0",
@ -206,6 +207,12 @@
"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": {
"version": "1.11.6",
"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",
"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": {
"version": "1.11.6",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz",

@ -6,6 +6,7 @@
"main": "index.js",
"description": "Generating a Website from a Markdown Generator",
"dependencies": {
"crypto": "^1.0.1",
"dayjs": "^1.11.6",
"fast-xml-parser": "^4.0.11",
"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 %}
<img src="{{ page.media.teaser.src | media }}" />
<img src="{{ page.media.teaser.src | resize({ width: 100 }) }}" />
{{ page.content | safe }}
{% 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 { 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
@ -18,13 +19,19 @@ class Engine {
// merge options
this._options = Object.assign({}, {
autoescapes: true,
throwOnUndefined: true
throwOnUndefined: true,
web: {
async: true
}
}, options)
this.nunjucks = nunjucks.configure(views, this._options)
this.nunjucks.addFilter('media', function(options) {
return media(options)
})
this.nunjucks.addFilter('resize', (...args) => {
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
this._defaults = {
@ -41,12 +48,11 @@ class Engine {
* @return {string}
*
*/
render(view, data) {
render(view, data, done) {
data = Object.assign({}, data, this._defaults)
return minify(this.nunjucks.render(view, data), {
removeComments: true,
collapseWhitespace: true
this.nunjucks.render(view, data, (error, response) => {
done(error, response)
})
}

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

@ -1,8 +1,7 @@
import path from 'path'
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
@ -19,7 +18,7 @@ function asset(staticPath)
let result = staticPath
// path to mix-manifest
const file = basePath + 'mix-manifest.json'
const file = path.join(path.resolve()) + 'mix-manifest.json'
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)
console.log(path.resolve(src))
sharp(src)
.toFile('output.png', (error, info) => { console.log(error) })
const media = new Media()
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 slugify from 'slugify'
import merge from 'lodash.merge'
import nunjucks from 'nunjucks'
import parseMarkdownFile from './../parsers/markdown.js'
@ -53,7 +54,7 @@ class Page {
* @return {string}
*
*/
render(engine) {
render(engine, done) {
const page = Object.assign({}, this._fields)
@ -61,11 +62,9 @@ class Page {
page.blocks = this._blocks
page.path = this.pathname + '/' + this.filename
const result = engine.render(this._fields.view, {
return engine.render(this._fields.view, {
page: page
})
return result
}, done)
}
/**

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Loading…
Cancel
Save