├── renovate.json
├── test
├── fixture
│ ├── pages
│ │ ├── index.vue
│ │ └── error.vue
│ └── nuxt.config.js
└── module.test.js
├── jest.config.js
├── .gitignore
├── .eslintrc.js
├── .editorconfig
├── CHANGELOG.md
├── .circleci
└── config.yml
├── LICENSE
├── package.json
├── lib
└── module.js
└── README.md
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "@nuxtjs"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/test/fixture/pages/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | testEnvironment: "node",
3 | collectCoverage: true
4 | }
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.iml
3 | .idea
4 | *.log*
5 | .nuxt
6 | .vscode
7 | .DS_STORE
8 | coverage
9 | dist
10 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parserOptions: {
4 | parser: 'babel-eslint',
5 | sourceType: 'module'
6 | },
7 | extends: '@nuxtjs'
8 | }
9 |
--------------------------------------------------------------------------------
/test/fixture/pages/error.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_size = 2
6 | indent_style = space
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
--------------------------------------------------------------------------------
/test/fixture/nuxt.config.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path')
2 |
3 | module.exports = {
4 | rootDir: resolve(__dirname, '../..'),
5 | buildDir: resolve(__dirname, '.nuxt'),
6 | srcDir: __dirname,
7 | dev: false,
8 | modules: [
9 | ['@@', {
10 | logHtml: true
11 | }]
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4 |
5 | ### [0.1.2](https://github.com/nuxt-community/html-minifier-module/compare/v0.1.1...v0.1.2) (2019-07-30)
6 |
7 | ## [0.1.1](https://github.com/nuxt-community/html-minifier-module/compare/v0.1.0...v0.1.1) (2019-04-26)
8 |
9 |
10 |
11 |
12 | # 0.1.0 (2019-01-17)
13 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | build:
4 | working_directory: ~/app
5 | docker:
6 | - image: circleci/node:10.16.0
7 | steps:
8 | # Checkout repository
9 | - checkout
10 |
11 | # Restore cache
12 | - restore_cache:
13 | key: yarn-{{ checksum "yarn.lock" }}
14 |
15 | # Install dependencies
16 | - run:
17 | name: Install Dependencies
18 | command: NODE_ENV=dev yarn
19 |
20 | # Keep cache
21 | - save_cache:
22 | key: yarn-{{ checksum "yarn.lock" }}
23 | paths:
24 | - "node_modules"
25 |
26 | # Test
27 | - run:
28 | name: Tests
29 | command: yarn test
30 |
31 | # Coverage
32 | - run:
33 | name: Coverage
34 | command: yarn codecov
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@nuxtjs/html-minifier",
3 | "version": "0.1.2",
4 | "description": "",
5 | "license": "MIT",
6 | "contributors": [
7 | "pimlie "
8 | ],
9 | "main": "lib/module.js",
10 | "repository": "https://github.com/nuxt-community/html-minifier-module",
11 | "publishConfig": {
12 | "access": "public"
13 | },
14 | "scripts": {
15 | "dev": "test/fixture",
16 | "lint": "eslint lib test",
17 | "test": "jest test",
18 | "release": "yarn lint && yarn test && standard-version"
19 | },
20 | "files": [
21 | "lib"
22 | ],
23 | "dependencies": {
24 | "consola": "^2.15.0",
25 | "figures": "^3.2.0",
26 | "html-minifier": "^4.0.0"
27 | },
28 | "devDependencies": {
29 | "@nuxtjs/eslint-config": "^1.1.2",
30 | "babel-eslint": "^10.1.0",
31 | "codecov": "3.8.1",
32 | "eslint": "^6.8.0",
33 | "eslint-config-standard": "^13.0.1",
34 | "eslint-loader": "^2.2.1",
35 | "eslint-plugin-import": "^2.22.1",
36 | "eslint-plugin-jest": "^22.21.0",
37 | "eslint-plugin-node": "^9.2.0",
38 | "eslint-plugin-promise": "^4.2.1",
39 | "eslint-plugin-standard": "^4.1.0",
40 | "eslint-plugin-vue": "^5.2.3",
41 | "get-port": "^5.1.1",
42 | "jest": "24.9.0",
43 | "nuxt-edge": "^2.9.0-26104328.b22e0543",
44 | "request-promise-native": "^1.0.9",
45 | "standard-version": "7.1.0"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/lib/module.js:
--------------------------------------------------------------------------------
1 | import consola from 'consola'
2 |
3 | const defaultOptions = {
4 | keepTrying: true,
5 | log: 'always',
6 | logHtml: false
7 | }
8 |
9 | export default function htmlMinificationModule (moduleOptions) {
10 | // only add hook when server is ready we could
11 | this.nuxt.hook('render:done', async () => {
12 | const htmlMinifier = await import('html-minifier')
13 | const figures = await import('figures')
14 |
15 | this.options.cli.badgeMessages.push(`${figures.radioOn} HTML minification enabled`)
16 |
17 | const options = Object.assign({}, defaultOptions, moduleOptions)
18 | if (options.log && !['always', 'once'].includes(options.log)) {
19 | options.log = defaultOptions.log
20 | }
21 |
22 | const minifierErrors = []
23 | this.nuxt.hook('render:route', (url, result, context) => {
24 | if (options.keepTrying || !minifierErrors.includes(url)) {
25 | try {
26 | const html = htmlMinifier.minify(result.html, this.options.build.html.minify)
27 | result.html = html
28 | } catch (err) { /* istanbul ignore next */
29 | if (this.options.dev || options.log === 'always' || (options.log === 'once' && !minifierErrors.includes(url))) {
30 | consola.error(`HTML minification failed for ${url}.` + (options.logHtml ? ` Failed HTML:\n ${result.html}` : ''))
31 | }
32 |
33 | // keep track of url's with minifier errors when needed
34 | if (!options.keepTrying || options.log === 'once') {
35 | minifierErrors.push(url)
36 | }
37 | }
38 | }
39 | })
40 | })
41 | }
42 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | :warning: This module is experimental, try it and let us know how it performs
2 |
3 | # @nuxtjs/html-minifier
4 | [](https://npmjs.com/package/@nuxtjs/html-minifier)
5 | [](https://npmjs.com/package/@nuxtjs/html-minifier)
6 | [](https://circleci.com/gh/nuxt-community/html-minifier-module)
7 |
8 | Minify the html for each request served by nuxt server (`nuxt start`)
9 |
10 | > :information_source: `nuxt generate` already has built-in support for minifying html
11 |
12 | > :fire: Using this module could be a performance hit :fire:
13 | > it is recommended to only use it when you have a caching proxy in front of your Nuxt server (at least until we have benchmarks to determine the real world impact)
14 |
15 | ## Usage
16 |
17 | `yarn add @nuxtjs/html-minifier` OR `npm i @nuxtjs/html-minifier`
18 |
19 | Add `@nuxtjs/html-minifier` to `modules` section of `nuxt.config.js`
20 |
21 | ```js
22 | {
23 | modules: [
24 | ['@nuxtjs/html-minifier', { log: 'once', logHtml: true }]
25 | ]
26 | }
27 | ```
28 |
29 | ## Options
30 |
31 | ### `keepTrying`
32 |
33 | - Default: `true`
34 |
35 | If `false` then every url which generated an error wont be minified in future requests
36 |
37 | ### `log`
38 | - Default: `always`
39 |
40 | - `always`: always log html-minifier errors
41 | - `once`: only log html-minifier errors once for each url
42 | - `false`: never log html-minifier errors
43 |
44 |
45 | ### `logHtml`
46 | - Default: `false`
47 |
48 | > Be wary to enable this in production, your disk could fill up quickly!
49 |
50 | If `true` then the html which failed to minimize is also logged
51 |
52 | ## HTML Minifier options
53 |
54 | This module uses the [`build.html.minify`](https://nuxtjs.org/api/configuration-build#html-minify) property for configuring html minifier
55 |
56 | ## Development
57 |
58 | - Clone this repository
59 | - Install dependencies using `yarn install` or `npm install`
60 | - Start development server using `npm run dev`
61 |
62 | ## License
63 |
64 | [MIT License](./LICENSE)
65 |
66 | Copyright (c) Nuxt Community.
67 |
--------------------------------------------------------------------------------
/test/module.test.js:
--------------------------------------------------------------------------------
1 | const consola = require('consola')
2 | jest.mock('consola')
3 | global.consola = consola
4 |
5 | const { Nuxt, Builder } = require('nuxt-edge')
6 | const getPort = require('get-port')
7 | const rp = require('request-promise-native')
8 |
9 | jest.setTimeout(120000)
10 |
11 | jest.mock('consola')
12 |
13 | const config = require('./fixture/nuxt.config')
14 |
15 | let port
16 | const url = path => `http://localhost:${port}${path}`
17 |
18 | describe('html-minifier-module', () => {
19 | let nuxt
20 |
21 | beforeAll(async () => {
22 | port = await getPort()
23 |
24 | nuxt = new Nuxt(config)
25 | await new Builder(nuxt).build()
26 | await nuxt.server.listen(port, 'localhost')
27 | })
28 |
29 | afterAll(async () => {
30 | await nuxt.close()
31 | })
32 |
33 | afterEach(() => {
34 | jest.clearAllMocks()
35 | })
36 |
37 | describe('always with logHtml', () => {
38 | test('html is minified', async () => {
39 | const html = await rp(url('/'))
40 | expect(html).not.toContain('hidden="true"')
41 | })
42 |
43 | test('returns html with error', async () => {
44 | const html = await rp(url('/error'))
45 | expect(html).toContain('
{
49 | const html = await rp(url('/error'))
50 | expect(html).toContain('
{
58 | const html = await rp(url('/error'))
59 | expect(html).toContain('
{
68 | beforeAll(async () => {
69 | await nuxt.close()
70 |
71 | config.modules[0][1] = { log: 'once' }
72 | nuxt = new Nuxt(config)
73 | await nuxt.server.listen(port, 'localhost')
74 | })
75 |
76 | test('html is minified', async () => {
77 | const html = await rp(url('/'))
78 | expect(html).not.toContain('hidden="true"')
79 | })
80 |
81 | test('logs error and doesnt prints html', async () => {
82 | const html = await rp(url('/error'))
83 | expect(html).toContain('
{
91 | const html = await rp(url('/error'))
92 | expect(html).toContain('
{
99 | beforeAll(async () => {
100 | await nuxt.close()
101 |
102 | config.modules[0][1] = { log: false }
103 | nuxt = new Nuxt(config)
104 | await nuxt.server.listen(port, 'localhost')
105 | })
106 |
107 | test('html is minified', async () => {
108 | const html = await rp(url('/'))
109 | expect(html).not.toContain('hidden="true"')
110 | })
111 |
112 | test('doesnt log error with consola', async () => {
113 | const html = await rp(url('/error'))
114 | expect(html).toContain('
{
120 | const html = await rp(url('/error'))
121 | expect(html).toContain('
{
128 | beforeAll(async () => {
129 | await nuxt.close()
130 |
131 | config.modules[0][1] = { keepTrying: false, log: 'always' }
132 | nuxt = new Nuxt(config)
133 | await nuxt.server.listen(port, 'localhost')
134 | })
135 |
136 | test('html is minified', async () => {
137 | const html = await rp(url('/'))
138 | expect(html).not.toContain('hidden="true"')
139 | })
140 |
141 | test('logs error with consola', async () => {
142 | const html = await rp(url('/error'))
143 | expect(html).toContain('
{
150 | const html = await rp(url('/error'))
151 | expect(html).toContain('