mirror of https://github.com/curbengh/hexo-yam
feat: minify json
This commit is contained in:
parent
64ba16cb22
commit
fdcdbef4a1
24
README.md
24
README.md
|
@ -7,7 +7,7 @@
|
|||
[![Known Vulnerabilities](https://snyk.io/test/npm/hexo-yam/badge.svg)](https://snyk.io/test/npm/hexo-yam)
|
||||
[![Greenkeeper badge](https://badges.greenkeeper.io/curbengh/hexo-yam.svg)](https://greenkeeper.io/)
|
||||
|
||||
Yet Another Minifier for Hexo. Minify and compress HTML, JS, CSS and SVG. XML, JSON and [many more](https://github.com/curbengh/hexo-yam/blob/ba77db0094a7c07ea9f70f010bfc15541d4105ca/index.js#L64) are also compressed. Support gzip and [brotli](https://en.wikipedia.org/wiki/Brotli) [compressions](https://en.wikipedia.org/wiki/HTTP_compression).
|
||||
Yet Another Minifier for Hexo. Minify and compress HTML, JS, CSS, SVG, XML and JSON. [Other files](https://github.com/curbengh/hexo-yam/blob/ba77db0094a7c07ea9f70f010bfc15541d4105ca/index.js#L64) are also compressed. Support gzip and [brotli](https://en.wikipedia.org/wiki/Brotli) [compressions](https://en.wikipedia.org/wiki/HTTP_compression).
|
||||
|
||||
|
||||
## Table of contents
|
||||
|
@ -22,6 +22,7 @@ Yet Another Minifier for Hexo. Minify and compress HTML, JS, CSS and SVG. XML, J
|
|||
- [Gzip](#gzip)
|
||||
- [Brotli](#brotli)
|
||||
- [XML](#xml)
|
||||
- [JSON](#json)
|
||||
- [Globbing](#globbing)
|
||||
- [HTTP Compression](#http-compression)
|
||||
|
||||
|
@ -194,6 +195,8 @@ minify:
|
|||
|
||||
## XML
|
||||
|
||||
Remove whitespaces in xml.
|
||||
|
||||
``` yaml
|
||||
minify:
|
||||
xml:
|
||||
|
@ -210,6 +213,25 @@ minify:
|
|||
- **removeComments** - Remove [comments](https://developer.mozilla.org/en-US/docs/Web/XML/XML_introduction) in xml. Defaults to `true`.
|
||||
- **globOptions** - See [globbing](#globbing) section.
|
||||
|
||||
## JSON
|
||||
|
||||
Remove whitespaces in json.
|
||||
|
||||
``` yaml
|
||||
minify:
|
||||
json:
|
||||
enable: false
|
||||
include:
|
||||
- '*.json'
|
||||
- '!*.min.json'
|
||||
```
|
||||
- **enable** - Enable the plugin. Defaults to `false`.
|
||||
- **priority** - Plugin's priority. Defaults to `10`.
|
||||
- **verbose** - Verbose output. Defaults to `false`.
|
||||
- **include** - Include files. Support [wildcard](http://www.globtester.com/) pattern(s) in a string or array.
|
||||
- Exclude `*.min.json` by default.
|
||||
- **globOptions** - See [globbing](#globbing) section.
|
||||
|
||||
## Globbing
|
||||
|
||||
Use "globOptions" to customise how glob patterns match files. Refer to [micromatch](https://github.com/micromatch/micromatch#options) for available options.
|
||||
|
|
12
index.js
12
index.js
|
@ -67,6 +67,13 @@ const xmlDefault = {
|
|||
removeComments: true,
|
||||
globOptions: { basename: true }
|
||||
}
|
||||
const jsonDefault = {
|
||||
enable: false,
|
||||
priority: 10,
|
||||
verbose: false,
|
||||
include: ['*.json', '!*.min.json'],
|
||||
globOptions: { basename: true }
|
||||
}
|
||||
|
||||
hexo.config.minify = Object.assign(minifyDefault, hexo.config.minify)
|
||||
hexo.config.minify.html = Object.assign(htmlDefault, hexo.config.minify.html)
|
||||
|
@ -76,6 +83,7 @@ hexo.config.minify.svg = Object.assign(svgDefault, hexo.config.minify.svg)
|
|||
hexo.config.minify.gzip = Object.assign(gzipDefault, hexo.config.minify.gzip)
|
||||
hexo.config.minify.brotli = Object.assign(brotliDefault, hexo.config.minify.brotli)
|
||||
hexo.config.minify.xml = Object.assign(xmlDefault, hexo.config.minify.xml)
|
||||
hexo.config.minify.json = Object.assign(jsonDefault, hexo.config.minify.json)
|
||||
|
||||
if (hexo.config.minify.enable === true) {
|
||||
const filter = require('./lib/filter')
|
||||
|
@ -86,6 +94,7 @@ if (hexo.config.minify.enable === true) {
|
|||
hexo.extend.filter.register('after_generate', filter.gzipFn, hexo.config.minify.gzip.priority)
|
||||
hexo.extend.filter.register('after_generate', filter.brotliFn, hexo.config.minify.brotli.priority)
|
||||
hexo.extend.filter.register('after_generate', filter.minifyXml, hexo.config.minify.xml.priority)
|
||||
hexo.extend.filter.register('after_generate', filter.minifyJson, hexo.config.minify.json.priority)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
@ -96,5 +105,6 @@ module.exports = {
|
|||
svgDefault,
|
||||
gzipDefault,
|
||||
brotliDefault,
|
||||
xmlDefault
|
||||
xmlDefault,
|
||||
jsonDefault
|
||||
}
|
||||
|
|
|
@ -253,6 +253,36 @@ function minifyXml () {
|
|||
}))
|
||||
}
|
||||
|
||||
function minifyJson () {
|
||||
const hexo = this
|
||||
const options = hexo.config.minify.json
|
||||
if (options.enable === false) return
|
||||
|
||||
const { route } = hexo
|
||||
const routeList = route.list()
|
||||
const { globOptions, include, verbose } = options
|
||||
|
||||
return Promise.all((match(routeList, include, globOptions)).map((path) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const assetPath = route.get(path)
|
||||
let assetTxt = ''
|
||||
assetPath.on('data', (chunk) => (assetTxt += chunk))
|
||||
assetPath.on('end', () => {
|
||||
if (assetTxt.length) {
|
||||
try {
|
||||
const result = JSON.stringify(JSON.parse(assetTxt))
|
||||
if (verbose) logFn.call(this, assetTxt, result, path, 'json')
|
||||
resolve(route.set(path, result))
|
||||
} catch (err) {
|
||||
reject(new Error(err))
|
||||
}
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
minifyHtml,
|
||||
minifyCss,
|
||||
|
@ -260,5 +290,6 @@ module.exports = {
|
|||
minifySvg,
|
||||
gzipFn,
|
||||
brotliFn,
|
||||
minifyXml
|
||||
minifyXml,
|
||||
minifyJson
|
||||
}
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
/* eslint-env jest */
|
||||
'use strict'
|
||||
|
||||
const Hexo = require('hexo')
|
||||
const hexo = new Hexo(__dirname)
|
||||
global.hexo = hexo
|
||||
const { jsonDefault } = require('../index')
|
||||
const jsonFn = require('../lib/filter').minifyJson.bind(hexo)
|
||||
const path = 'foo.json'
|
||||
const input = '{\n\t"vitae": "hendrerit",\n\t"tristique": [\n\t\t"primis",\n\t\t"quam"\n\t]\n}'
|
||||
const expected = '{"vitae":"hendrerit","tristique":["primis","quam"]}'
|
||||
|
||||
describe('xml', () => {
|
||||
beforeEach(() => {
|
||||
hexo.config.minify.json = Object.assign({}, jsonDefault)
|
||||
// plugin is disabled by default
|
||||
hexo.config.minify.json.enable = true
|
||||
hexo.route.set(path, input)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
const routeList = hexo.route.list()
|
||||
routeList.forEach((path) => hexo.route.remove(path))
|
||||
})
|
||||
|
||||
test('default', async () => {
|
||||
await jsonFn()
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
})
|
||||
|
||||
test('disable', async () => {
|
||||
hexo.config.minify.json.enable = false
|
||||
const result = await jsonFn()
|
||||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
test('option - verbose', async () => {
|
||||
hexo.config.minify.json.verbose = true
|
||||
hexo.log.log = jest.fn()
|
||||
await jsonFn()
|
||||
|
||||
expect(hexo.log.log.mock.calls[0][0]).toContain(`json: ${path}`)
|
||||
})
|
||||
|
||||
test('invalid input', async () => {
|
||||
hexo.route.set(path, 'foo')
|
||||
try {
|
||||
await jsonFn()
|
||||
} catch (err) {
|
||||
expect(err.message).toContain('SyntaxError')
|
||||
}
|
||||
})
|
||||
|
||||
test('empty file', async () => {
|
||||
hexo.route.set(path, '')
|
||||
const result = await jsonFn()
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result[0]).toBeUndefined()
|
||||
})
|
||||
|
||||
test('include - exclude *.min.json by default', async () => {
|
||||
const path = 'foo.min.json'
|
||||
hexo.route.set(path, input)
|
||||
await jsonFn()
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(input)
|
||||
})
|
||||
})
|
||||
|
||||
test('include - basename', async () => {
|
||||
hexo.config.minify.json.include = 'bar.json'
|
||||
const path = 'foo/bar.json'
|
||||
hexo.route.set(path, input)
|
||||
await jsonFn()
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
})
|
||||
|
||||
test('include - slash in pattern', async () => {
|
||||
hexo.config.minify.json.include = '**/lectus/**/*.json'
|
||||
const path = 'eleifend/lectus/nullam/dapibus/netus.json'
|
||||
hexo.route.set(path, input)
|
||||
await jsonFn()
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
})
|
||||
|
||||
test('include - basename + slash', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const paths = [
|
||||
'lorem/ipsum/dolor.json',
|
||||
'gravida/sociis/erat/ante.json',
|
||||
'aptent/elementum.json',
|
||||
'felis/blandit/cursus.json'
|
||||
]
|
||||
hexo.config.minify.json.include = [
|
||||
'dolor.json',
|
||||
'**/sociis/**/*.json'
|
||||
]
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
hexo.route.set(inpath, input)
|
||||
})
|
||||
await jsonFn()
|
||||
|
||||
const minPaths = paths.slice(0, 2)
|
||||
const unminPaths = paths.slice(2)
|
||||
|
||||
minPaths.forEach((inpath) => {
|
||||
const output = hexo.route.get(inpath)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
})
|
||||
|
||||
unminPaths.forEach((inpath) => {
|
||||
const output = hexo.route.get(inpath)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(input)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('include - reverse pattern + basename disabled', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const paths = [
|
||||
'lorem/ipsum/dolor.json',
|
||||
'gravida/sociis/erat/ante.json',
|
||||
'aptent/elementum.json',
|
||||
'felis/blandit/cursus.json'
|
||||
]
|
||||
hexo.config.minify.json.include = [
|
||||
'!dolor.json'
|
||||
]
|
||||
hexo.config.minify.json.globOptions = {
|
||||
basename: false
|
||||
}
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
hexo.route.set(inpath, input)
|
||||
})
|
||||
await jsonFn()
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
const output = hexo.route.get(inpath)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('include - empty route', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const result = await jsonFn()
|
||||
expect(result.length).toBe(0)
|
||||
})
|
||||
})
|
Loading…
Reference in New Issue