mirror of https://github.com/curbengh/hexo-yam
Compare commits
No commits in common. "master" and "v8.0.0" have entirely different histories.
|
|
@ -6,17 +6,19 @@ jobs:
|
||||||
linter:
|
linter:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v3
|
||||||
- name: Install Bun
|
- name: Use Node.js 14.x
|
||||||
uses: oven-sh/setup-bun@v2
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '14.x'
|
||||||
- name: Cache NPM dependencies
|
- name: Cache NPM dependencies
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: node_modules
|
path: node_modules
|
||||||
key: ${{ runner.os }}-npm-cache
|
key: ${{ runner.os }}-npm-cache
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-npm-cache
|
${{ runner.os }}-npm-cache
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: bun install
|
run: npm install
|
||||||
- name: Lint
|
- name: Lint
|
||||||
run: bun run lint
|
run: npm run lint
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,16 @@ on:
|
||||||
- .github/workflows/semgrep.yml
|
- .github/workflows/semgrep.yml
|
||||||
schedule:
|
schedule:
|
||||||
# Weekly
|
# Weekly
|
||||||
- cron: "0 0 * * 0"
|
- cron: '0 0 * * 0'
|
||||||
jobs:
|
jobs:
|
||||||
semgrep:
|
semgrep:
|
||||||
name: Scan
|
name: Scan
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-20.04
|
||||||
env:
|
env:
|
||||||
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
|
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
|
||||||
container:
|
container:
|
||||||
image: returntocorp/semgrep
|
image: returntocorp/semgrep
|
||||||
if: (github.actor != 'dependabot[bot]')
|
if: (github.actor != 'dependabot[bot]')
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v3
|
||||||
- run: semgrep ci
|
- run: semgrep ci
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,22 @@ name: Snyk
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
# Weekly
|
# Weekly
|
||||||
- cron: "0 0 * * 0"
|
- cron: '0 0 * * 0'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- "dependabot/github_actions/github/codeql-action**"
|
- 'dependabot/github_actions/github/codeql-action**'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
security:
|
security:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v3
|
||||||
- name: Install Bun
|
- name: Use Node.js 16.x
|
||||||
uses: oven-sh/setup-bun@v2
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '16.x'
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: bun install
|
run: npm install
|
||||||
- name: Run Snyk to check for vulnerabilities
|
- name: Run Snyk to check for vulnerabilities
|
||||||
uses: snyk/actions/node@master
|
uses: snyk/actions/node@master
|
||||||
continue-on-error: true # To make sure that SARIF upload gets called
|
continue-on-error: true # To make sure that SARIF upload gets called
|
||||||
|
|
@ -26,7 +28,7 @@ jobs:
|
||||||
command: test
|
command: test
|
||||||
args: --sarif-file-output=snyk.sarif
|
args: --sarif-file-output=snyk.sarif
|
||||||
- name: Upload result to GitHub Code Scanning
|
- name: Upload result to GitHub Code Scanning
|
||||||
uses: github/codeql-action/upload-sarif@v3
|
uses: github/codeql-action/upload-sarif@v2
|
||||||
with:
|
with:
|
||||||
sarif_file: snyk.sarif
|
sarif_file: snyk.sarif
|
||||||
- name: Monitor for vulnerabilities
|
- name: Monitor for vulnerabilities
|
||||||
|
|
|
||||||
|
|
@ -8,45 +8,51 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
node-version: ["20", "22", "24"]
|
node-version: ['14', '16', '18', '19']
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v3
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
- name: Cache NPM dependencies
|
- name: Cache NPM dependencies
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: node_modules
|
path: node_modules
|
||||||
key: ${{ runner.os }}-npm-cache
|
key: ${{ runner.os }}-npm-cache
|
||||||
restore-keys: ${{ runner.os }}-npm-cache
|
restore-keys: ${{ runner.os }}-npm-cache
|
||||||
- name: Determine unrs-resolver binary version
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
case "$RUNNER_OS" in
|
|
||||||
"Linux")
|
|
||||||
echo "PLATFORM=linux-x64-gnu" >> "$GITHUB_ENV" ;;
|
|
||||||
"Windows")
|
|
||||||
echo "PLATFORM=win32-x64-msvc" >> "$GITHUB_ENV" ;;
|
|
||||||
"macOS")
|
|
||||||
echo "PLATFORM=darwin-arm64" >> "$GITHUB_ENV" ;;
|
|
||||||
esac
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
shell: bash
|
run: npm install
|
||||||
run: |
|
|
||||||
npm install
|
|
||||||
npm install --include=optional --force @mongodb-js/zstd
|
|
||||||
npm install "@unrs/resolver-binding-$PLATFORM"
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: npm run test
|
run: npm run test
|
||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
|
coverage:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
node-version: ['14.x']
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
- name: Cache NPM dependencies
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: node_modules
|
||||||
|
key: ${{ runner.os }}-npm-cache
|
||||||
|
restore-keys: ${{ runner.os }}-npm-cache
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: npm install
|
||||||
|
- name: Coverage
|
||||||
|
run: npm run test
|
||||||
|
env:
|
||||||
|
CI: true
|
||||||
- name: Upload coverage report to Codecov
|
- name: Upload coverage report to Codecov
|
||||||
if: matrix.os == 'ubuntu-latest' && matrix.node-version == '22'
|
uses: codecov/codecov-action@v3
|
||||||
uses: codecov/codecov-action@v5
|
|
||||||
with:
|
with:
|
||||||
fail_ci_if_error: true
|
fail_ci_if_error: true
|
||||||
env:
|
|
||||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,3 @@ package-lock.json
|
||||||
tmp/
|
tmp/
|
||||||
*.log
|
*.log
|
||||||
coverage/
|
coverage/
|
||||||
bun.lockb
|
|
||||||
|
|
|
||||||
2
LICENSE
2
LICENSE
|
|
@ -1,6 +1,6 @@
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2018-2024 curbengh, 2016-2018 rozbo
|
Copyright (c) 2018-2019 curbengh, 2016-2018 rozbo
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
||||||
236
README.md
236
README.md
|
|
@ -1,12 +1,15 @@
|
||||||
# hexo-yam
|
# hexo-yam
|
||||||
|
|
||||||
[](https://www.npmjs.com/package/hexo-yam)
|
[](https://www.npmjs.com/package/hexo-yam)
|
||||||
[](https://github.com/curbengh/hexo-yam/actions?query=workflow%3ATester)
|
[](https://github.com/curbengh/hexo-yam/actions?query=workflow%3ATester)
|
||||||
[](https://codecov.io/gh/curbengh/hexo-yam)
|
[](https://codecov.io/gh/curbengh/hexo-yam)
|
||||||
[](https://libraries.io/npm/hexo-yam)
|
[](https://libraries.io/npm/hexo-yam)
|
||||||
[](https://snyk.io/test/github/curbengh/hexo-yam)
|
[](https://snyk.io/test/npm/hexo-yam)
|
||||||
|
[](https://lgtm.com/projects/g/curbengh/hexo-yam/alerts/)
|
||||||
|
[](https://lgtm.com/projects/g/curbengh/hexo-yam/context:javascript)
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
Yet Another Minifier for Hexo. Minify HTML, JS, CSS, SVG, XML and JSON. Compress static [web assets](https://github.com/curbengh/hexo-yam/blob/ba77db0094a7c07ea9f70f010bfc15541d4105ca/index.js#L64) using gzip, brotli and zstd.
|
|
||||||
|
|
||||||
## Table of contents
|
## Table of contents
|
||||||
|
|
||||||
|
|
@ -16,25 +19,23 @@ Yet Another Minifier for Hexo. Minify HTML, JS, CSS, SVG, XML and JSON. Compress
|
||||||
- [CSS](#css)
|
- [CSS](#css)
|
||||||
- [JS](#js)
|
- [JS](#js)
|
||||||
- [SVG](#svg)
|
- [SVG](#svg)
|
||||||
- [XML](#xml)
|
|
||||||
- [JSON](#json)
|
|
||||||
- [Gzip](#gzip)
|
- [Gzip](#gzip)
|
||||||
- [Brotli](#brotli)
|
- [Brotli](#brotli)
|
||||||
- [Zstd](#zstd)
|
- [XML](#xml)
|
||||||
|
- [JSON](#json)
|
||||||
- [Globbing](#globbing)
|
- [Globbing](#globbing)
|
||||||
|
- [HTTP Compression](#http-compression)
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
``` bash
|
||||||
```bash
|
$ npm install hexo-yam --save
|
||||||
$ npm install --save hexo-yam
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
```yaml
|
``` yaml
|
||||||
minify:
|
minify:
|
||||||
enable: true
|
enable: true
|
||||||
previewServer: true
|
|
||||||
html:
|
html:
|
||||||
css:
|
css:
|
||||||
js:
|
js:
|
||||||
|
|
@ -46,7 +47,6 @@ minify:
|
||||||
```
|
```
|
||||||
|
|
||||||
- **enable** - Enable the plugin. Defaults to `true`.
|
- **enable** - Enable the plugin. Defaults to `true`.
|
||||||
- **previewServer** - Disable the plugin when running `hexo server`. Defaults to `true`.
|
|
||||||
- **html** - See [HTML](#html) section
|
- **html** - See [HTML](#html) section
|
||||||
- **css** - See [CSS](#css) section
|
- **css** - See [CSS](#css) section
|
||||||
- **js** - See [JS](#js) section
|
- **js** - See [JS](#js) section
|
||||||
|
|
@ -58,13 +58,12 @@ minify:
|
||||||
|
|
||||||
## HTML
|
## HTML
|
||||||
|
|
||||||
```yaml
|
``` yaml
|
||||||
minify:
|
minify:
|
||||||
html:
|
html:
|
||||||
enable: true
|
enable: true
|
||||||
exclude:
|
exclude:
|
||||||
```
|
```
|
||||||
|
|
||||||
- **enable** - Enable the plugin. Defaults to `true`.
|
- **enable** - Enable the plugin. Defaults to `true`.
|
||||||
- **priority** - Plugin's priority. Defaults to `10`. Set lower value to set higher priority and vice versa.
|
- **priority** - Plugin's priority. Defaults to `10`. Set lower value to set higher priority and vice versa.
|
||||||
- **verbose** - Verbose output. Defaults to `false`.
|
- **verbose** - Verbose output. Defaults to `false`.
|
||||||
|
|
@ -75,14 +74,13 @@ For more options, see [HTMLMinifier](https://github.com/kangax/html-minifier).
|
||||||
|
|
||||||
## CSS
|
## CSS
|
||||||
|
|
||||||
```yaml
|
``` yaml
|
||||||
minify:
|
minify:
|
||||||
css:
|
css:
|
||||||
enable: true
|
enable: true
|
||||||
exclude:
|
exclude:
|
||||||
- "*.min.css"
|
- '*.min.css'
|
||||||
```
|
```
|
||||||
|
|
||||||
- **enable** - Enable the plugin. Defaults to `true`.
|
- **enable** - Enable the plugin. Defaults to `true`.
|
||||||
- **priority** - Plugin's priority. Defaults to `10`.
|
- **priority** - Plugin's priority. Defaults to `10`.
|
||||||
- **verbose** - Verbose output. Defaults to `false`.
|
- **verbose** - Verbose output. Defaults to `false`.
|
||||||
|
|
@ -94,14 +92,13 @@ For more options, see [clean-css](https://github.com/jakubpawlowicz/clean-css).
|
||||||
|
|
||||||
## JS
|
## JS
|
||||||
|
|
||||||
```yaml
|
``` yaml
|
||||||
minify:
|
minify:
|
||||||
js:
|
js:
|
||||||
enable: true
|
enable: true
|
||||||
exclude:
|
exclude:
|
||||||
- "*.min.js"
|
- '*.min.js'
|
||||||
```
|
```
|
||||||
|
|
||||||
- **enable** - Enable the plugin. Defaults to `true`.
|
- **enable** - Enable the plugin. Defaults to `true`.
|
||||||
- **priority** - Plugin's priority. Defaults to `10`.
|
- **priority** - Plugin's priority. Defaults to `10`.
|
||||||
- **verbose** - Verbose output. Defaults to `false`.
|
- **verbose** - Verbose output. Defaults to `false`.
|
||||||
|
|
@ -116,15 +113,14 @@ For more options, see [Terser](https://github.com/terser-js/terser).
|
||||||
|
|
||||||
## SVG
|
## SVG
|
||||||
|
|
||||||
```yaml
|
``` yaml
|
||||||
minify:
|
minify:
|
||||||
svg:
|
svg:
|
||||||
enable: true
|
enable: true
|
||||||
include:
|
include:
|
||||||
- "*.svg"
|
- '*.svg'
|
||||||
- "!*.min.svg"
|
- '!*.min.svg'
|
||||||
```
|
```
|
||||||
|
|
||||||
- **enable** - Enable the plugin. Defaults to `true`.
|
- **enable** - Enable the plugin. Defaults to `true`.
|
||||||
- **priority** - Plugin's priority. Defaults to `10`.
|
- **priority** - Plugin's priority. Defaults to `10`.
|
||||||
- **verbose** - Verbose output. Defaults to `false`.
|
- **verbose** - Verbose output. Defaults to `false`.
|
||||||
|
|
@ -132,7 +128,7 @@ minify:
|
||||||
- Exclude `*.min.svg` by default.
|
- Exclude `*.min.svg` by default.
|
||||||
- **plugins** - Plugin options.
|
- **plugins** - Plugin options.
|
||||||
- Examples:
|
- Examples:
|
||||||
```yaml
|
``` yaml
|
||||||
plugins:
|
plugins:
|
||||||
# Retain comments
|
# Retain comments
|
||||||
removeComments: false
|
removeComments: false
|
||||||
|
|
@ -142,19 +138,72 @@ minify:
|
||||||
- For more options, see [svgo](https://github.com/svg/svgo).
|
- For more options, see [svgo](https://github.com/svg/svgo).
|
||||||
- **globOptions** - See [globbing](#globbing) section.
|
- **globOptions** - See [globbing](#globbing) section.
|
||||||
|
|
||||||
|
## Gzip
|
||||||
|
|
||||||
|
``` yaml
|
||||||
|
minify:
|
||||||
|
gzip:
|
||||||
|
enable: true
|
||||||
|
include:
|
||||||
|
- '*.html'
|
||||||
|
- '*.css'
|
||||||
|
- '*.js'
|
||||||
|
- '*.txt'
|
||||||
|
- '*.ttf'
|
||||||
|
- '*.atom'
|
||||||
|
- '*.stl'
|
||||||
|
- '*.xml'
|
||||||
|
- '*.svg'
|
||||||
|
- '*.eot'
|
||||||
|
- '*.json'
|
||||||
|
```
|
||||||
|
- **enable** - Enable the plugin. Defaults to `true`.
|
||||||
|
- **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.
|
||||||
|
- Support one-liner, `include: ['*.html','*.css','*.js']`.
|
||||||
|
- Must include asterisk and single quotes. `.html` is invalid. `'*.html'` is valid.
|
||||||
|
- **globOptions** - See [globbing](#globbing) section.
|
||||||
|
- **level** - Compression level; lower value may results in faster compression but slightly larger (compressed) file. Range `1-9`. Defaults to `9`, or the value of [`zlib.constants.Z_BEST_COMPRESSION`](https://nodejs.org/docs/latest-v12.x/api/zlib.html#zlib_zlib_constants)
|
||||||
|
|
||||||
|
## Brotli
|
||||||
|
|
||||||
|
``` yaml
|
||||||
|
minify:
|
||||||
|
brotli:
|
||||||
|
enable: true
|
||||||
|
include:
|
||||||
|
- '*.html'
|
||||||
|
- '*.css'
|
||||||
|
- '*.js'
|
||||||
|
- '*.txt'
|
||||||
|
- '*.ttf'
|
||||||
|
- '*.atom'
|
||||||
|
- '*.stl'
|
||||||
|
- '*.xml'
|
||||||
|
- '*.svg'
|
||||||
|
- '*.eot'
|
||||||
|
- '*.json'
|
||||||
|
```
|
||||||
|
- **enable** - Enable the plugin. Defaults to `true`.
|
||||||
|
- **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.
|
||||||
|
- **globOptions** - See [globbing](#globbing) section.
|
||||||
|
- **level** - Compression level. Range `1-11`. Defaults to `11`, or the value of [`zlib.constants.BROTLI_MAX_QUALITY`](https://nodejs.org/docs/latest-v12.x/api/zlib.html#zlib_brotli_constants)
|
||||||
|
|
||||||
## XML
|
## XML
|
||||||
|
|
||||||
Remove whitespaces in xml.
|
Remove whitespaces in xml.
|
||||||
|
|
||||||
```yaml
|
``` yaml
|
||||||
minify:
|
minify:
|
||||||
xml:
|
xml:
|
||||||
enable: false
|
enable: false
|
||||||
include:
|
include:
|
||||||
- "*.xml"
|
- '*.xml'
|
||||||
- "!*.min.xml"
|
- '!*.min.xml'
|
||||||
```
|
```
|
||||||
|
|
||||||
- **enable** - Enable the plugin. Defaults to `false`.
|
- **enable** - Enable the plugin. Defaults to `false`.
|
||||||
- **priority** - Plugin's priority. Defaults to `10`.
|
- **priority** - Plugin's priority. Defaults to `10`.
|
||||||
- **verbose** - Verbose output. Defaults to `false`.
|
- **verbose** - Verbose output. Defaults to `false`.
|
||||||
|
|
@ -169,15 +218,14 @@ For more options, see [minify-xml](https://github.com/kristian/minify-xml#option
|
||||||
|
|
||||||
Remove whitespaces in json.
|
Remove whitespaces in json.
|
||||||
|
|
||||||
```yaml
|
``` yaml
|
||||||
minify:
|
minify:
|
||||||
json:
|
json:
|
||||||
enable: false
|
enable: false
|
||||||
include:
|
include:
|
||||||
- "*.json"
|
- '*.json'
|
||||||
- "!*.min.json"
|
- '!*.min.json'
|
||||||
```
|
```
|
||||||
|
|
||||||
- **enable** - Enable the plugin. Defaults to `false`.
|
- **enable** - Enable the plugin. Defaults to `false`.
|
||||||
- **priority** - Plugin's priority. Defaults to `10`.
|
- **priority** - Plugin's priority. Defaults to `10`.
|
||||||
- **verbose** - Verbose output. Defaults to `false`.
|
- **verbose** - Verbose output. Defaults to `false`.
|
||||||
|
|
@ -185,89 +233,6 @@ minify:
|
||||||
- Exclude `*.min.json` by default.
|
- Exclude `*.min.json` by default.
|
||||||
- **globOptions** - See [globbing](#globbing) section.
|
- **globOptions** - See [globbing](#globbing) section.
|
||||||
|
|
||||||
## Gzip
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
minify:
|
|
||||||
gzip:
|
|
||||||
enable: true
|
|
||||||
include:
|
|
||||||
- "*.html"
|
|
||||||
- "*.css"
|
|
||||||
- "*.js"
|
|
||||||
- "*.txt"
|
|
||||||
- "*.ttf"
|
|
||||||
- "*.atom"
|
|
||||||
- "*.stl"
|
|
||||||
- "*.xml"
|
|
||||||
- "*.svg"
|
|
||||||
- "*.eot"
|
|
||||||
- "*.json"
|
|
||||||
```
|
|
||||||
|
|
||||||
- **enable** - Enable the plugin. Defaults to `true`.
|
|
||||||
- **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.
|
|
||||||
- Support one-liner, `include: ['*.html','*.css','*.js']`.
|
|
||||||
- Must include asterisk and single quotes. `.html` is invalid. `'*.html'` is valid.
|
|
||||||
- **globOptions** - See [globbing](#globbing) section.
|
|
||||||
- **level** - Compression level; lower value may results in faster compression but slightly larger (compressed) file. Range `1-9`. Defaults to `9`, or the value of [`zlib.constants.Z_BEST_COMPRESSION`](https://nodejs.org/docs/latest-v12.x/api/zlib.html#zlib_zlib_constants)
|
|
||||||
|
|
||||||
## Brotli
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
minify:
|
|
||||||
brotli:
|
|
||||||
enable: true
|
|
||||||
include:
|
|
||||||
- "*.html"
|
|
||||||
- "*.css"
|
|
||||||
- "*.js"
|
|
||||||
- "*.txt"
|
|
||||||
- "*.ttf"
|
|
||||||
- "*.atom"
|
|
||||||
- "*.stl"
|
|
||||||
- "*.xml"
|
|
||||||
- "*.svg"
|
|
||||||
- "*.eot"
|
|
||||||
- "*.json"
|
|
||||||
```
|
|
||||||
|
|
||||||
- **enable** - Enable the plugin. Defaults to `true`.
|
|
||||||
- **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.
|
|
||||||
- **globOptions** - See [globbing](#globbing) section.
|
|
||||||
- **level** - Compression level. Range `1-11`. Defaults to `11`, or the value of [`zlib.constants.BROTLI_MAX_QUALITY`](https://nodejs.org/docs/latest-v12.x/api/zlib.html#zlib_brotli_constants)
|
|
||||||
|
|
||||||
## Zstd
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
minify:
|
|
||||||
zstd:
|
|
||||||
enable: false
|
|
||||||
include:
|
|
||||||
- "*.html"
|
|
||||||
- "*.css"
|
|
||||||
- "*.js"
|
|
||||||
- "*.txt"
|
|
||||||
- "*.ttf"
|
|
||||||
- "*.atom"
|
|
||||||
- "*.stl"
|
|
||||||
- "*.xml"
|
|
||||||
- "*.svg"
|
|
||||||
- "*.eot"
|
|
||||||
- "*.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.
|
|
||||||
- **globOptions** - See [globbing](#globbing) section.
|
|
||||||
- **level** - Compression level. Range `1-22`. Defaults to `3`, or the value of [`DEFAULT_LEVEL`](https://github.com/mongodb-js/zstd/blob/a3a08c61c9045411c8275e248498dbc583457fb5/src/lib.rs#L9)
|
|
||||||
|
|
||||||
## Globbing
|
## Globbing
|
||||||
|
|
||||||
Use "globOptions" to customise how glob patterns match files. Refer to [micromatch](https://github.com/micromatch/micromatch#options) for available options.
|
Use "globOptions" to customise how glob patterns match files. Refer to [micromatch](https://github.com/micromatch/micromatch#options) for available options.
|
||||||
|
|
@ -276,32 +241,51 @@ Use "globOptions" to customise how glob patterns match files. Refer to [micromat
|
||||||
- basename is disabled depending on each pattern.
|
- basename is disabled depending on each pattern.
|
||||||
- This means the following options would work,
|
- This means the following options would work,
|
||||||
|
|
||||||
```yml
|
``` yml
|
||||||
exclude:
|
exclude:
|
||||||
- "*foo.html" # basename is enabled
|
- '*foo.html' # basename is enabled
|
||||||
- "**/bar/*/*.html" # basename is automatically disabled
|
- '**/bar/*/*.html' # basename is automatically disabled
|
||||||
- "*baz.css" # basename is enabled
|
- '*baz.css' # basename is enabled
|
||||||
globOptions:
|
globOptions:
|
||||||
basename: true # default
|
basename: true # default
|
||||||
```
|
```
|
||||||
|
|
||||||
- This behaviour doesn't apply to pattern that starts with `!` (negation).
|
- This behaviour doesn't apply to pattern that starts with `!` (negation).
|
||||||
- This limitation only applies to `include:` option used in svg, gzip and brotli.
|
- This limitation only applies to `include:` option used in svg, gzip and brotli.
|
||||||
- This means the following options would _not_ work,
|
- This means the following options would *not* work,
|
||||||
|
|
||||||
```yml
|
``` yml
|
||||||
include:
|
include:
|
||||||
- "!foo.svg"
|
- '!foo.svg'
|
||||||
- "!**/bar/*/*.svg"
|
- '!**/bar/*/*.svg'
|
||||||
globOptions:
|
globOptions:
|
||||||
basename: true
|
basename: true
|
||||||
```
|
```
|
||||||
|
|
||||||
- basename will stay disabled, if explicitly disabled in "globOptions".
|
- basename will stay disabled, if explicitly disabled in "globOptions".
|
||||||
|
|
||||||
|
|
||||||
|
## HTTP Compression
|
||||||
|
|
||||||
|
While most modern web browsers [support Brotli](https://www.caniuse.com/#feat=brotli), you also need to consider whether the web/app server, hosting platform, reverse proxy or CDN (whichever relevant to you) support it.
|
||||||
|
|
||||||
|
Brotli support as of May 2022:
|
||||||
|
|
||||||
|
Name | Brotli support
|
||||||
|
--- | ---
|
||||||
|
GitHub Pages | [In consideration](https://github.community/t5/GitHub-Pages/Support-for-pre-compressed-assets-and-brotli-compression/m-p/22055)
|
||||||
|
GitLab Pages | Yes
|
||||||
|
Netlify | Yes
|
||||||
|
Hexo Server | [In progress](https://github.com/hexojs/hexo-server/pull/100)
|
||||||
|
|
||||||
|
If you have access to the web server config, you should disable on-the-fly compression for static files (that are already compressed by this plugin),
|
||||||
|
|
||||||
|
- [Caddy](https://caddyserver.com/features): [0.9.4+](https://caddyserver.com/blog/caddy-0_9_4-released) by default support pre-compressed `.gz` `.br` files and on-the-fly gzip compress dynamic files. [v2.4.0+](https://github.com/caddyserver/caddy/releases/tag/v2.4.0-beta.2) requires specifying the [`precompressed`](https://caddyserver.com/docs/caddyfile/directives/file_server) option.
|
||||||
|
- [nginx](https://github.com/google/ngx_brotli): Make sure both filter and static modules are enabled. This way pre-compressed `.br` files will be served while dynamic content can be compressed on-the-fly. Protip: `brotli_types text/plain text/css application/javascript application/json image/svg+xml application/xml+rss;` to prevent compressing media files (which are already compressed anyway).
|
||||||
|
- [Apache](https://httpd.apache.org/docs/2.4/en/mod/mod_brotli.html): See 'Serving pre-compressed content' section of [mod_brotli](https://httpd.apache.org/docs/2.4/en/mod/mod_brotli.html).
|
||||||
|
- [express](https://github.com/expressjs/express)/[connect](https://github.com/senchalabs/connect): Use [pre-compressed-assets](https://github.com/domadams/pre-compressed-assets). You still can continue to use [compression](https://github.com/expressjs/compression)/[shrink-ray-current](https://github.com/Alorel/shrink-ray) for dynamic files.
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
All credits go to the following work:
|
All credits go to the following work:
|
||||||
|
|
||||||
- [hexo-neat](https://github.com/rozbo/hexo-neat) by rozbo
|
- [hexo-neat](https://github.com/rozbo/hexo-neat) by rozbo
|
||||||
- gzip feature is inspired by [hexo-generator-optimize](https://github.com/JackyRen/hexo-generator-optimize)
|
- gzip feature is inspired by [hexo-generator-optimize](https://github.com/JackyRen/hexo-generator-optimize)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
[install]
|
|
||||||
optional = false
|
|
||||||
|
|
||||||
[install.lockfile]
|
|
||||||
save = false
|
|
||||||
14
index.js
14
index.js
|
|
@ -2,8 +2,7 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
hexo.config.minify = Object.assign({
|
hexo.config.minify = Object.assign({
|
||||||
enable: true,
|
enable: true
|
||||||
previewServer: true
|
|
||||||
}, hexo.config.minify)
|
}, hexo.config.minify)
|
||||||
|
|
||||||
hexo.config.minify.html = Object.assign({
|
hexo.config.minify.html = Object.assign({
|
||||||
|
|
@ -69,14 +68,6 @@ hexo.config.minify.brotli = Object.assign({
|
||||||
globOptions: { basename: true }
|
globOptions: { basename: true }
|
||||||
}, hexo.config.minify.brotli)
|
}, hexo.config.minify.brotli)
|
||||||
|
|
||||||
hexo.config.minify.zstd = Object.assign({
|
|
||||||
enable: false,
|
|
||||||
priority: 10,
|
|
||||||
verbose: false,
|
|
||||||
include: ['*.html', '*.css', '*.js', '*.txt', '*.ttf', '*.atom', '*.stl', '*.xml', '*.svg', '*.eot', '*.json'],
|
|
||||||
globOptions: { basename: true }
|
|
||||||
}, hexo.config.minify.zstd)
|
|
||||||
|
|
||||||
hexo.config.minify.xml = Object.assign({
|
hexo.config.minify.xml = Object.assign({
|
||||||
enable: false,
|
enable: false,
|
||||||
priority: 10,
|
priority: 10,
|
||||||
|
|
@ -94,7 +85,7 @@ hexo.config.minify.json = Object.assign({
|
||||||
globOptions: { basename: true }
|
globOptions: { basename: true }
|
||||||
}, hexo.config.minify.json)
|
}, hexo.config.minify.json)
|
||||||
|
|
||||||
if (hexo.config.minify.enable === true && !(hexo.config.minify.previewServer === true && ['s', 'server'].includes(hexo.env.cmd))) {
|
if (hexo.config.minify.enable === true) {
|
||||||
const filter = require('./lib/filter')
|
const filter = require('./lib/filter')
|
||||||
hexo.extend.filter.register('after_render:html', filter.minifyHtml, hexo.config.minify.html.priority)
|
hexo.extend.filter.register('after_render:html', filter.minifyHtml, hexo.config.minify.html.priority)
|
||||||
hexo.extend.filter.register('after_render:css', filter.minifyCss, hexo.config.minify.css.priority)
|
hexo.extend.filter.register('after_render:css', filter.minifyCss, hexo.config.minify.css.priority)
|
||||||
|
|
@ -102,7 +93,6 @@ if (hexo.config.minify.enable === true && !(hexo.config.minify.previewServer ===
|
||||||
hexo.extend.filter.register('after_generate', filter.minifySvg, hexo.config.minify.svg.priority)
|
hexo.extend.filter.register('after_generate', filter.minifySvg, hexo.config.minify.svg.priority)
|
||||||
hexo.extend.filter.register('after_generate', filter.gzipFn, hexo.config.minify.gzip.priority)
|
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.brotliFn, hexo.config.minify.brotli.priority)
|
||||||
hexo.extend.filter.register('after_generate', filter.zstdFn, hexo.config.minify.zstd.priority)
|
|
||||||
hexo.extend.filter.register('after_generate', filter.minifyXml, hexo.config.minify.xml.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)
|
hexo.extend.filter.register('after_generate', filter.minifyJson, hexo.config.minify.json.priority)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const { minify: htmlMinify } = require('html-minifier-terser')
|
const { minify: htmlMinify } = require('html-minifier')
|
||||||
const CleanCSS = require('clean-css')
|
const CleanCSS = require('clean-css')
|
||||||
const { minify: terserMinify } = require('terser')
|
const { minify: terserMinify } = require('terser')
|
||||||
const { optimize: svgOptimize } = require('svgo')
|
const { optimize: svgOptimize } = require('svgo')
|
||||||
const zlib = require('node:zlib')
|
const zlib = require('zlib')
|
||||||
const { promisify } = require('node:util')
|
const { promisify } = require('util')
|
||||||
const gzip = promisify(zlib.gzip)
|
const gzip = promisify(zlib.gzip)
|
||||||
const br = promisify(zlib.brotliCompress)
|
const br = promisify(zlib.brotliCompress)
|
||||||
const { minify: compressXml } = require('minify-xml')
|
const { minify: compressXml } = require('minify-xml')
|
||||||
const micromatch = require('micromatch')
|
const micromatch = require('micromatch')
|
||||||
const { compress: zstd } = require('@mongodb-js/zstd')
|
|
||||||
|
|
||||||
const isMatch = (path = '', patterns = [], options = {}) => {
|
const isMatch = (path = '', patterns = [], options = {}) => {
|
||||||
if (path && patterns) {
|
if (path && patterns) {
|
||||||
|
|
@ -60,7 +59,7 @@ function logFn (original, minified, path, ext) {
|
||||||
log.log(`${ext}: ${path} [${saved}% saved]`)
|
log.log(`${ext}: ${path} [${saved}% saved]`)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function minifyHtml (str, data) {
|
function minifyHtml (str, data) {
|
||||||
const hexo = this
|
const hexo = this
|
||||||
const options = hexo.config.minify.html
|
const options = hexo.config.minify.html
|
||||||
if (options.enable === false || !str) return
|
if (options.enable === false || !str) return
|
||||||
|
|
@ -72,7 +71,7 @@ async function minifyHtml (str, data) {
|
||||||
if (isMatch(path, exclude, globOptions)) return str
|
if (isMatch(path, exclude, globOptions)) return str
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await htmlMinify(str, options)
|
const result = htmlMinify(str, options)
|
||||||
if (verbose) logFn.call(this, str, result, path, 'html')
|
if (verbose) logFn.call(this, str, result, path, 'html')
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
@ -231,39 +230,6 @@ function brotliFn () {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
function zstdFn () {
|
|
||||||
const hexo = this
|
|
||||||
const options = hexo.config.minify.zstd
|
|
||||||
if (options.enable === false) return
|
|
||||||
|
|
||||||
const { route } = hexo
|
|
||||||
const routeList = route.list()
|
|
||||||
const { globOptions, include, verbose } = options
|
|
||||||
let { level } = options
|
|
||||||
if (typeof level !== 'number') level = undefined
|
|
||||||
|
|
||||||
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', async () => {
|
|
||||||
if (assetTxt.length) {
|
|
||||||
try {
|
|
||||||
const input = Buffer.from(assetTxt, 'utf-8')
|
|
||||||
const result = await zstd(input, level)
|
|
||||||
if (verbose) logFn.call(this, assetTxt, result, path, 'zstd')
|
|
||||||
resolve(route.set(path + '.zst', result))
|
|
||||||
} catch (err) {
|
|
||||||
reject(new Error(`Path: ${path}\n${err}`))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
function minifyXml () {
|
function minifyXml () {
|
||||||
const hexo = this
|
const hexo = this
|
||||||
const options = hexo.config.minify.xml
|
const options = hexo.config.minify.xml
|
||||||
|
|
@ -331,7 +297,6 @@ module.exports = {
|
||||||
minifySvg,
|
minifySvg,
|
||||||
gzipFn,
|
gzipFn,
|
||||||
brotliFn,
|
brotliFn,
|
||||||
zstdFn,
|
|
||||||
minifyXml,
|
minifyXml,
|
||||||
minifyJson
|
minifyJson
|
||||||
}
|
}
|
||||||
|
|
|
||||||
32
package.json
32
package.json
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "hexo-yam",
|
"name": "hexo-yam",
|
||||||
"description": "Yet Another Minifier. Minify and compress html, js, css, svg, xml and json",
|
"description": "Yet Another Minifier. Minify and compress html, js, css, svg, xml and json",
|
||||||
"version": "9.0.0",
|
"version": "8.0.0",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
|
|
@ -16,35 +16,36 @@
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 20.9.0"
|
"node": ">= 14.15.0"
|
||||||
},
|
},
|
||||||
"author": "curben",
|
"author": "curben",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"homepage": "https://github.com/curbengh/hexo-yam",
|
"homepage": "https://github.com/curbengh/hexo-yam",
|
||||||
"repository": {
|
"repository": "curbengh/hexo-yam",
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/curbengh/hexo-yam.git"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"clean-css": "^5.1.2",
|
"clean-css": "^5.1.2",
|
||||||
"html-minifier-terser": "^7.2.0",
|
"html-minifier": "^4.0.0",
|
||||||
"micromatch": "^4.0.2",
|
"micromatch": "^4.0.2",
|
||||||
"minify-xml": "^3.2.0",
|
"minify-xml": "^3.2.0",
|
||||||
"svgo": "^4.0.0",
|
"svgo": "^3.0.0",
|
||||||
"terser": "^5.3.0",
|
"terser": "^5.3.0"
|
||||||
"@mongodb-js/zstd": "^2.0.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"hexo": "^7.1.0",
|
"hexo": "^6.1.0",
|
||||||
"jest": "^30.0.4",
|
"jest": "^29.1.2",
|
||||||
"standard": "^17.0.0"
|
"standard": "^17.0.0"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
"html",
|
||||||
|
"js",
|
||||||
|
"css",
|
||||||
|
"svg",
|
||||||
|
"xml",
|
||||||
|
"json",
|
||||||
"minify",
|
"minify",
|
||||||
"compress",
|
"compress",
|
||||||
"gzip",
|
"gzip",
|
||||||
"brotli",
|
"brotli",
|
||||||
"zstd",
|
|
||||||
"hexo-yam",
|
"hexo-yam",
|
||||||
"hexo"
|
"hexo"
|
||||||
],
|
],
|
||||||
|
|
@ -52,9 +53,6 @@
|
||||||
"clearMocks": true,
|
"clearMocks": true,
|
||||||
"collectCoverage": true,
|
"collectCoverage": true,
|
||||||
"coverageDirectory": "./coverage/",
|
"coverageDirectory": "./coverage/",
|
||||||
"testEnvironment": "node",
|
"testEnvironment": "node"
|
||||||
"testEnvironmentOptions": {
|
|
||||||
"globalsCleanup": "off"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const Hexo = require('hexo')
|
const Hexo = require('hexo')
|
||||||
const zlib = require('node:zlib')
|
const zlib = require('zlib')
|
||||||
const { promisify } = require('node:util')
|
const { promisify } = require('util')
|
||||||
const brotli = promisify(zlib.brotliCompress)
|
const brotli = promisify(zlib.brotliCompress)
|
||||||
const unbrotli = promisify(zlib.brotliDecompress)
|
const unbrotli = promisify(zlib.brotliDecompress)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const Hexo = require('hexo')
|
const Hexo = require('hexo')
|
||||||
const zlib = require('node:zlib')
|
const zlib = require('zlib')
|
||||||
const { promisify } = require('node:util')
|
const { promisify } = require('util')
|
||||||
const gzip = promisify(zlib.gzip)
|
const gzip = promisify(zlib.gzip)
|
||||||
const unzip = promisify(zlib.unzip)
|
const unzip = promisify(zlib.unzip)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const Hexo = require('hexo')
|
const Hexo = require('hexo')
|
||||||
const { minify: htmlMinify } = require('html-minifier-terser')
|
const { minify: htmlMinify } = require('html-minifier')
|
||||||
|
|
||||||
describe('html', () => {
|
describe('html', () => {
|
||||||
const hexo = new Hexo(__dirname)
|
const hexo = new Hexo(__dirname)
|
||||||
|
|
@ -26,107 +26,105 @@ describe('html', () => {
|
||||||
globOptions: { basename: true }
|
globOptions: { basename: true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let expected = ''
|
const expected = htmlMinify(input, defaultCfg.html)
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
expected = await htmlMinify(input, defaultCfg.html)
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
hexo.config.minify = JSON.parse(JSON.stringify(defaultCfg))
|
hexo.config.minify = JSON.parse(JSON.stringify(defaultCfg))
|
||||||
})
|
})
|
||||||
|
|
||||||
test('default', async () => {
|
test('default', () => {
|
||||||
const result = await h(input, { path })
|
const result = h(input, { path })
|
||||||
|
|
||||||
expect(result).toBe(expected)
|
expect(result).toBe(expected)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('disable', async () => {
|
test('disable', () => {
|
||||||
hexo.config.minify.html.enable = false
|
hexo.config.minify.html.enable = false
|
||||||
|
|
||||||
const result = await h(input, { path })
|
const result = h(input, { path })
|
||||||
|
|
||||||
expect(result).toBeUndefined()
|
expect(result).toBeUndefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('empty file', async () => {
|
test('empty file', () => {
|
||||||
const result = await h('', { path })
|
const result = h('', { path })
|
||||||
|
|
||||||
expect(result).toBeUndefined()
|
expect(result).toBeUndefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('option', async () => {
|
test('option', () => {
|
||||||
const customOpt = { removeEmptyAttributes: false }
|
const customOpt = { removeEmptyAttributes: false }
|
||||||
hexo.config.minify.html = customOpt
|
hexo.config.minify.html = customOpt
|
||||||
|
|
||||||
const result = await h(input, { path })
|
const result = h(input, { path })
|
||||||
const expected = await htmlMinify(input, customOpt)
|
const expected = htmlMinify(input, customOpt)
|
||||||
|
|
||||||
expect(result).toBe(input)
|
expect(result).toBe(input)
|
||||||
expect(result).toBe(expected)
|
expect(result).toBe(expected)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('option - verbose', async () => {
|
test('option - verbose', () => {
|
||||||
hexo.config.minify.html.verbose = true
|
hexo.config.minify.html.verbose = true
|
||||||
hexo.log.log = jest.fn()
|
hexo.log.log = jest.fn()
|
||||||
await h(input, { path })
|
h(input, { path })
|
||||||
|
|
||||||
expect(hexo.log.log.mock.calls[0][0]).toContain(`html: ${path}`)
|
expect(hexo.log.log.mock.calls[0][0]).toContain(`html: ${path}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('exclude', async () => {
|
test('exclude', () => {
|
||||||
const exclude = '*.min.html'
|
const exclude = '*.min.html'
|
||||||
hexo.config.minify.html.exclude = exclude
|
hexo.config.minify.html.exclude = exclude
|
||||||
|
|
||||||
const result = await h(input, { path: 'foo/bar.min.html' })
|
const result = h(input, { path: 'foo/bar.min.html' })
|
||||||
|
|
||||||
expect(result).toBe(input)
|
expect(result).toBe(input)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('exclude - slash in pattern', async () => {
|
test('exclude - slash in pattern', () => {
|
||||||
const exclude = '**/lectus/**/*.html'
|
const exclude = '**/lectus/**/*.html'
|
||||||
hexo.config.minify.html.exclude = exclude
|
hexo.config.minify.html.exclude = exclude
|
||||||
|
|
||||||
const result = await h(input, { path: 'eleifend/lectus/nullam/dapibus/netus.html' })
|
const result = h(input, { path: 'eleifend/lectus/nullam/dapibus/netus.html' })
|
||||||
|
|
||||||
expect(result).toBe(input)
|
expect(result).toBe(input)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('exclude - basename is true + slash', async () => {
|
test('exclude - basename is true + slash', () => {
|
||||||
const exclude = ['**/lectus/**/*.html', 'bar.html']
|
const exclude = ['**/lectus/**/*.html', 'bar.html']
|
||||||
const globOptions = { basename: true }
|
const globOptions = { basename: true }
|
||||||
hexo.config.minify.html.exclude = exclude
|
hexo.config.minify.html.exclude = exclude
|
||||||
hexo.config.minify.html.globOptions = globOptions
|
hexo.config.minify.html.globOptions = globOptions
|
||||||
|
|
||||||
const result = await h(input, { path: 'foo/bar.html' })
|
const result = h(input, { path: 'foo/bar.html' })
|
||||||
|
|
||||||
expect(result).toBe(input)
|
expect(result).toBe(input)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('exclude - basename is false + slash', async () => {
|
test('exclude - basename is false + slash', () => {
|
||||||
const exclude = ['**/lectus/**/*.html', 'bar.html']
|
const exclude = ['**/lectus/**/*.html', 'bar.html']
|
||||||
const globOptions = { basename: false }
|
const globOptions = { basename: false }
|
||||||
hexo.config.minify.html.exclude = exclude
|
hexo.config.minify.html.exclude = exclude
|
||||||
hexo.config.minify.html.globOptions = globOptions
|
hexo.config.minify.html.globOptions = globOptions
|
||||||
|
|
||||||
const result = await h(input, { path: 'foo/bar.html' })
|
const result = h(input, { path: 'foo/bar.html' })
|
||||||
|
|
||||||
expect(result).toBe(expected)
|
expect(result).toBe(expected)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('null', async () => {
|
test('null', () => {
|
||||||
hexo.config.minify.html.exclude = null
|
hexo.config.minify.html.exclude = null
|
||||||
hexo.config.minify.html.globOptions = null
|
hexo.config.minify.html.globOptions = null
|
||||||
|
|
||||||
const result = await h(input, { path: null })
|
const result = h(input, { path: null })
|
||||||
|
|
||||||
expect(result).toBe(expected)
|
expect(result).toBe(expected)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('invalid string', async () => {
|
test('invalid string', () => {
|
||||||
const invalid = '<html><>?:"{}|_+</html>'
|
const invalid = '<html><>?:"{}|_+</html>'
|
||||||
|
|
||||||
await expect(h(invalid, { path })).rejects.toThrow('Parse Error: <>?:"{}|_+</html>')
|
expect(() => {
|
||||||
|
h(invalid, { path })
|
||||||
|
}).toThrow(`Path: ${path}\nError: Parse Error`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,256 +0,0 @@
|
||||||
/* eslint-env jest */
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
const Hexo = require('hexo')
|
|
||||||
const { compress: zstd, decompress: unzstd } = require('@mongodb-js/zstd')
|
|
||||||
|
|
||||||
describe('zstd', () => {
|
|
||||||
const hexo = new Hexo(__dirname)
|
|
||||||
const z = require('../lib/filter').zstdFn.bind(hexo)
|
|
||||||
const path = 'foo.txt'
|
|
||||||
const input = 'Lorem ipsum dolor sit amet consectetur adipiscing elit fusce'
|
|
||||||
const inputBuf = Buffer.from(input, 'utf8')
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
hexo.config.minify = {
|
|
||||||
zstd: {
|
|
||||||
enable: true,
|
|
||||||
verbose: false,
|
|
||||||
include: ['*.html', '*.css', '*.js', '*.txt', '*.ttf', '*.atom', '*.stl', '*.xml', '*.svg', '*.eot', '*.json'],
|
|
||||||
globOptions: { basename: true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hexo.route.set(path, input)
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
const routeList = hexo.route.list()
|
|
||||||
routeList.forEach((path) => hexo.route.remove(path))
|
|
||||||
})
|
|
||||||
|
|
||||||
test('default', async () => {
|
|
||||||
await z()
|
|
||||||
|
|
||||||
const output = hexo.route.get(path.concat('.zst'))
|
|
||||||
const buf = []
|
|
||||||
output.on('data', (chunk) => (buf.push(chunk)))
|
|
||||||
output.on('end', async () => {
|
|
||||||
const result = Buffer.concat(buf)
|
|
||||||
const expected = await zstd(inputBuf)
|
|
||||||
const resultUnzst = await unzstd(result)
|
|
||||||
const expectedUnzst = await unzstd(expected)
|
|
||||||
|
|
||||||
expect(result.equals(expected)).toBe(true)
|
|
||||||
expect(resultUnzst.toString()).toBe(input)
|
|
||||||
expect(expectedUnzst.toString()).toBe(input)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test('disable', async () => {
|
|
||||||
hexo.config.minify.zstd.enable = false
|
|
||||||
const result = await z()
|
|
||||||
|
|
||||||
expect(result).toBeUndefined()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('empty file', async () => {
|
|
||||||
hexo.route.set(path, '')
|
|
||||||
|
|
||||||
const routeList = hexo.route.list()
|
|
||||||
expect(routeList).not.toContain(path.concat('.zst'))
|
|
||||||
|
|
||||||
const result = await z()
|
|
||||||
expect(result).toBeDefined()
|
|
||||||
expect(result[0]).toBeUndefined()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('option', async () => {
|
|
||||||
const level = 1
|
|
||||||
hexo.config.minify.zstd.level = level
|
|
||||||
await z()
|
|
||||||
|
|
||||||
const output = hexo.route.get(path.concat('.zst'))
|
|
||||||
const buf = []
|
|
||||||
output.on('data', (chunk) => (buf.push(chunk)))
|
|
||||||
output.on('end', async () => {
|
|
||||||
const result = Buffer.concat(buf)
|
|
||||||
const expected = await zstd(inputBuf, level)
|
|
||||||
|
|
||||||
expect(result.equals(expected)).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test('option - verbose', async () => {
|
|
||||||
hexo.config.minify.zstd.verbose = true
|
|
||||||
hexo.log.log = jest.fn()
|
|
||||||
await z()
|
|
||||||
|
|
||||||
expect(hexo.log.log.mock.calls[0][0]).toContain(`zstd: ${path}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('option - level is string', async () => {
|
|
||||||
const level = 'foo'
|
|
||||||
hexo.config.minify.zstd.level = level
|
|
||||||
await z()
|
|
||||||
|
|
||||||
const output = hexo.route.get(path.concat('.zst'))
|
|
||||||
const buf = []
|
|
||||||
output.on('data', (chunk) => (buf.push(chunk)))
|
|
||||||
output.on('end', async () => {
|
|
||||||
const result = Buffer.concat(buf)
|
|
||||||
const expected = await zstd(inputBuf, undefined)
|
|
||||||
|
|
||||||
expect(result.equals(expected)).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test('include - exclude non-text file by default', async () => {
|
|
||||||
const path = 'foo.jpg'
|
|
||||||
hexo.route.set(path, input)
|
|
||||||
await z()
|
|
||||||
|
|
||||||
const result = hexo.route.get(path.concat('.zst'))
|
|
||||||
|
|
||||||
expect(result).toBeUndefined()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('include - basename', async () => {
|
|
||||||
hexo.config.minify.zstd.include = 'bar.txt'
|
|
||||||
const path = 'foo/bar.txt'
|
|
||||||
hexo.route.set(path, input)
|
|
||||||
await z()
|
|
||||||
|
|
||||||
const result = hexo.route.get(path.concat('.zst'))
|
|
||||||
|
|
||||||
expect(result).toBeDefined()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('include - slash in pattern', async () => {
|
|
||||||
hexo.config.minify.zstd.include = '**/lectus/**/*.txt'
|
|
||||||
const path = 'eleifend/lectus/nullam/dapibus/netus.txt'
|
|
||||||
hexo.route.set(path, input)
|
|
||||||
await z()
|
|
||||||
|
|
||||||
const result = hexo.route.get(path.concat('.zst'))
|
|
||||||
|
|
||||||
expect(result).toBeDefined()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('include - basename + slash + basename enabled', async () => {
|
|
||||||
hexo.route.remove(path)
|
|
||||||
|
|
||||||
const paths = [
|
|
||||||
'lorem/ipsum/dolor.html',
|
|
||||||
'gravida/sociis/erat/ante.css',
|
|
||||||
'aptent/elementum.js',
|
|
||||||
'felis/blandit/cursus.svg'
|
|
||||||
]
|
|
||||||
hexo.config.minify.zstd.include = [
|
|
||||||
'*.html',
|
|
||||||
'**/sociis/**/*.css'
|
|
||||||
]
|
|
||||||
|
|
||||||
paths.forEach((inpath) => {
|
|
||||||
hexo.route.set(inpath, input)
|
|
||||||
})
|
|
||||||
await z()
|
|
||||||
|
|
||||||
const routeList = hexo.route.list()
|
|
||||||
const expected = [
|
|
||||||
'lorem/ipsum/dolor.html.zst',
|
|
||||||
'gravida/sociis/erat/ante.css.zst'
|
|
||||||
]
|
|
||||||
const notExpected = [
|
|
||||||
'aptent/elementum.js.zst',
|
|
||||||
'felis/blandit/cursus.svg.zst'
|
|
||||||
]
|
|
||||||
|
|
||||||
expect(routeList).toEqual(expect.arrayContaining(expected))
|
|
||||||
expect(routeList).toEqual(expect.not.arrayContaining(notExpected))
|
|
||||||
})
|
|
||||||
|
|
||||||
test('include - basename + slash + basename disabled', async () => {
|
|
||||||
hexo.route.remove(path)
|
|
||||||
|
|
||||||
const paths = [
|
|
||||||
'lorem/ipsum/dolor.html',
|
|
||||||
'gravida/sociis/erat/ante.css',
|
|
||||||
'aptent/elementum.js',
|
|
||||||
'felis/blandit/cursus.svg'
|
|
||||||
]
|
|
||||||
hexo.config.minify.zstd.include = [
|
|
||||||
'*.html',
|
|
||||||
'**/sociis/**/*.css'
|
|
||||||
]
|
|
||||||
hexo.config.minify.zstd.globOptions = {
|
|
||||||
basename: false
|
|
||||||
}
|
|
||||||
|
|
||||||
paths.forEach((inpath) => {
|
|
||||||
hexo.route.set(inpath, input)
|
|
||||||
})
|
|
||||||
await z()
|
|
||||||
|
|
||||||
const routeList = hexo.route.list()
|
|
||||||
const expected = [
|
|
||||||
'gravida/sociis/erat/ante.css.zst'
|
|
||||||
]
|
|
||||||
const notExpected = [
|
|
||||||
'lorem/ipsum/dolor.html.zst',
|
|
||||||
'aptent/elementum.js.zst',
|
|
||||||
'felis/blandit/cursus.svg.zst'
|
|
||||||
]
|
|
||||||
|
|
||||||
expect(routeList).toEqual(expect.arrayContaining(expected))
|
|
||||||
expect(routeList).toEqual(expect.not.arrayContaining(notExpected))
|
|
||||||
})
|
|
||||||
|
|
||||||
test('include - reverse pattern + basename disabled', async () => {
|
|
||||||
hexo.route.remove(path)
|
|
||||||
|
|
||||||
const paths = [
|
|
||||||
'lorem/ipsum/dolor.html',
|
|
||||||
'gravida/sociis/erat/ante.css',
|
|
||||||
'aptent/elementum.js',
|
|
||||||
'felis/blandit/cursus.svg'
|
|
||||||
]
|
|
||||||
hexo.config.minify.zstd.include = [
|
|
||||||
'!dolor.html'
|
|
||||||
]
|
|
||||||
hexo.config.minify.zstd.globOptions = {
|
|
||||||
basename: false
|
|
||||||
}
|
|
||||||
|
|
||||||
paths.forEach((inpath) => {
|
|
||||||
hexo.route.set(inpath, input)
|
|
||||||
})
|
|
||||||
await z()
|
|
||||||
|
|
||||||
const routeList = hexo.route.list()
|
|
||||||
const expected = paths.map((path) => path.concat('.zst'))
|
|
||||||
|
|
||||||
expect(routeList).toEqual(expect.arrayContaining(expected))
|
|
||||||
})
|
|
||||||
|
|
||||||
test('blns', async () => {
|
|
||||||
const blns = require('./fixtures/blns.json')
|
|
||||||
|
|
||||||
for (const nStr of blns) {
|
|
||||||
hexo.route.remove(path)
|
|
||||||
|
|
||||||
hexo.route.set(path, nStr)
|
|
||||||
|
|
||||||
await z()
|
|
||||||
|
|
||||||
const output = hexo.route.get(path.concat('.zst'))
|
|
||||||
const buf = []
|
|
||||||
output.on('data', (chunk) => (buf.push(chunk)))
|
|
||||||
output.on('end', async () => {
|
|
||||||
const result = Buffer.concat(buf)
|
|
||||||
const resultUnzst = await unzstd(result)
|
|
||||||
|
|
||||||
expect(resultUnzst.toString()).toBe(nStr)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
Loading…
Reference in New Issue