mirror of
https://github.com/SamEyeBam/animate.git
synced 2026-03-30 09:38:08 +00:00
larry babby and threejs for glsl
This commit is contained in:
3
webGl/my-threejs-test/node_modules/htmlnano/.eslintignore
generated
vendored
Normal file
3
webGl/my-threejs-test/node_modules/htmlnano/.eslintignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
lib/modules/example.mjs
|
||||
test.mjs
|
||||
**/*.cjs
|
||||
390
webGl/my-threejs-test/node_modules/htmlnano/CHANGELOG.md
generated
vendored
Normal file
390
webGl/my-threejs-test/node_modules/htmlnano/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,390 @@
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [2.1.0] - 2023-10-19
|
||||
|
||||
### Added
|
||||
- Convert htmlnano to ES Modules [#260]
|
||||
|
||||
### Fixed
|
||||
- Collapse white spaces according to specs [#257]
|
||||
|
||||
|
||||
## [2.0.4] - 2023-04-15
|
||||
|
||||
### Fixed
|
||||
- Should not minify `<script>` and `<style>` with SRI [#220]
|
||||
- Should not merge `<style>` or `<script>` with SRI [#220]
|
||||
- Should not minify json with SRI [#220]
|
||||
|
||||
|
||||
## [2.0.3] - 2022-11-13
|
||||
|
||||
### Added
|
||||
- Minify function for `HtmlMinimizerWebpackPlugin`
|
||||
|
||||
### Fixed
|
||||
- `collapseWhitespace`: handle textNode when comment is preserved [#184]
|
||||
- `minifyUrls`: srcset & javascript: url [#185]
|
||||
- Correct missing value default usage
|
||||
- `collapseBooleanAttributes`: empty string attributes
|
||||
- Guard type of attributes' value [#195]
|
||||
- Do not choke on svg error [#197]
|
||||
|
||||
### Changed
|
||||
- Minify based on invalid value default
|
||||
- Avoid hardcoding preset keys
|
||||
|
||||
|
||||
## [2.0.2] - 2022-04-06
|
||||
|
||||
### Fixed
|
||||
- JSON-LD crash [#182]
|
||||
|
||||
|
||||
## [2.0.1] - 2022-04-04
|
||||
**This version contains a critical bug [#182].**
|
||||
**Don't use it.**
|
||||
|
||||
### Changed
|
||||
- Speed improvements [#127]
|
||||
- Fix `<img sizes>` [#180]
|
||||
|
||||
|
||||
## [2.0.0] - 2022-01-12
|
||||
*The major version has to be released because of vulnerability in PostCSS (see [#165])*
|
||||
|
||||
### Changed
|
||||
- Support optional dependencies [#168] (`minifyUrl`, ` minifyJs`, `removeUnusedCss`, `minifyCss`). *This might be a breaking change for you*. Check the docs: https://github.com/posthtml/htmlnano/pull/168/files
|
||||
- Disable `mergeScripts` & `mergeStyles` in the safe preset [#170].
|
||||
|
||||
|
||||
## [1.1.1] - 2021-09-19
|
||||
This version fixes fatal errors introduced in [1.1.0].
|
||||
|
||||
|
||||
## [1.1.0] - 2021-09-19
|
||||
*This version contains fatal errors. Please use [1.1.1] instead.*
|
||||
|
||||
### Added
|
||||
- Collapse missing value default attribute in `removeRedundantAttributes` [#158].
|
||||
- New `normalizeAttributeValues` module to normalize casing of attribute values [#163].
|
||||
- Custom matcher for `removeComments` [#156].
|
||||
|
||||
### Changed
|
||||
- Remove more empty attributes in `removeEmptyAttributes` [#161].
|
||||
- Enhance collapse whitespace in `collapseWhitespace` [#145].
|
||||
- `minifyJs` and `minifyUrls` enhancement [#159].
|
||||
- Enhance attribute collapse whitespace in `collapseAttributeWhitespace` [#157].
|
||||
|
||||
|
||||
|
||||
## [1.0.1] - 2021-09-11
|
||||
### Added
|
||||
- Support of [@novaatwarren/uncss](https://github.com/novaatwarren/uncss) fork [#154]
|
||||
|
||||
### Changed
|
||||
- SVGO plugins configuration [#153]
|
||||
|
||||
|
||||
|
||||
## [1.0.0] - 2021-04-17
|
||||
After more than 4 years of development, it's time to release a stable [1.0.0](https://github.com/posthtml/htmlnano/releases/tag/1.0.0) version 🎉
|
||||
|
||||
It doesn't contain anything new from the previous [0.2.9](https://github.com/posthtml/htmlnano/releases/tag/0.2.9) release.
|
||||
We just did a major upgrade of two dependencies: [PurgeCSS](https://purgecss.com/) and [SVGO](https://github.com/svg/svgo),
|
||||
which changed their config format.
|
||||
Thus we have to do a major release of `htmlnano`.
|
||||
|
||||
You can safely upgrade to `htmlnano@1.0.0` if you don't pass any config to `minifySvg` or `removeUnusedCss` (while used with PurgeCSS) modules.
|
||||
Otherwise, you have to adapt the config according to the new [PurgeCSS@3](https://github.com/FullHuman/purgecss/releases/tag/v3.0.0) and [SVGO@2](https://github.com/svg/svgo/releases/tag/v2.0.0) config format.
|
||||
|
||||
|
||||
|
||||
## [0.2.9] - 2021-04-11
|
||||
### Added
|
||||
- `minifyConditionalComment` support `<html>` [#125].
|
||||
- Minify JS within `<script type="module">` [#135].
|
||||
|
||||
### Fixed
|
||||
- `collapseWhitespaces` around comment [#120].
|
||||
- handle `CDATA` inside script correctly [#122].
|
||||
- Minify SVG correctly [#129].
|
||||
|
||||
### Changed
|
||||
- Upgrade to terser@5 (JS minification).
|
||||
|
||||
|
||||
|
||||
## [0.2.8] - 2020-11-15
|
||||
### Added
|
||||
- [`removeOptionalTags`](https://github.com/posthtml/htmlnano#removeoptionaltags) [#110].
|
||||
- [`sortAttributes`](https://github.com/posthtml/htmlnano#removeoptionaltags) [#113].
|
||||
- `source[src]` and `srcset` support to `minifyUrls` [#117].
|
||||
- [`minifyConditionalComments`](https://github.com/posthtml/htmlnano#minifyconditionalcomments) [#119].
|
||||
|
||||
### Changed
|
||||
- Sort by frequency `sortAttributesWithLists` [#111].
|
||||
- Strip more spaces in `collapseWhitespace` [#112].
|
||||
- Remove `loading="eager"` from `<img>` and `<iframe>` [#114].
|
||||
- Remove redundant `type` from `<script>` [#114].
|
||||
- Strip whitespaces between textnode and element [#116].
|
||||
|
||||
|
||||
|
||||
## [0.2.7] - 2020-10-17
|
||||
### Added
|
||||
- More aggressive whitespace removal option [#90].
|
||||
- Cloudflare SSE support to `removeComments` [#94].
|
||||
- Improve compression ratio by sorting attribute values [#95].
|
||||
- New `minifyUrls` module [#98].
|
||||
- New `removeAttributeQuotes` module [#104].
|
||||
- Remove `type=text/css` for `link[rel=stylesheet]` [#102].
|
||||
- Collapse `crossorigin` attributes [#107].
|
||||
- Exclude excerpt comment for common CMS [#108].
|
||||
|
||||
### Fixed
|
||||
- Keep JS inside SVG wrapped in `//<![CDATA[ //]]` [#88].
|
||||
|
||||
|
||||
## [0.2.6] - 2020-07-15
|
||||
### Added
|
||||
- Let PostHTML options to be passed.
|
||||
|
||||
### Fixed
|
||||
- `<script>` tags merging without content.
|
||||
|
||||
|
||||
## [0.2.5] - 2019-11-09
|
||||
### Added
|
||||
- Option to remove unused CSS using PurgeCSS [#84].
|
||||
|
||||
### Fixed
|
||||
- Keep the order of inline and external JS [#80].
|
||||
|
||||
|
||||
## [0.2.4] - 2019-07-11
|
||||
### Fixed
|
||||
- Remove crossorigin from boolean attribute [#78], [#79].
|
||||
- Disable SVGO plugin convertShapeToPath in safe preset [#76].
|
||||
|
||||
|
||||
## [0.2.3] - 2019-02-14
|
||||
### Fixed
|
||||
- Keep `<g>` in SVG by default [#71].
|
||||
|
||||
|
||||
## [0.2.2] - 2019-01-03
|
||||
### Added
|
||||
- `removeUnusedCss` module [#36].
|
||||
|
||||
### Fixed
|
||||
- Bug when `tag === false` [#66].
|
||||
- Add `crossorigin` to boolean attributes [#67].
|
||||
|
||||
|
||||
## [0.2.1] - 2018-12-01
|
||||
### Fixed
|
||||
- Disable JS minifying on AMP pages [#65].
|
||||
|
||||
## [0.2.0] - 2018-09-14
|
||||
### Breaking changes
|
||||
- The API of `minifyCss` module has been changed since `cssnano` has been updated to version 4, which has a different API. Check the following resources for more info:
|
||||
* [htmlnano docs](https://github.com/posthtml/htmlnano#minifycss)
|
||||
* [cssnano docs](https://cssnano.co/guides/presets)
|
||||
* Diff of commit [979f2c](https://github.com/posthtml/htmlnano/commit/979f2c821892c9e979e8b85f74ed0394330fceaf) with the changes of related docs.
|
||||
|
||||
### Added
|
||||
- Add presets [#64].
|
||||
- Add `collapseAttributeWhitespace` module for collapsing spaces in list-like attributes [#25].
|
||||
- Add `deduplicateAttributeValues` module for de-duplicating values in list-like attributes [#39].
|
||||
- Better support for AMP pages [#59].
|
||||
- Collapse whitespaces between top-level tags [#24].
|
||||
|
||||
### Changed
|
||||
- Improve whitespace normalization using `normalize-html-whitespace` [#21].
|
||||
|
||||
### Fixed
|
||||
- Don't collapse `visible="false"` attributes in A-Frame pages [#62].
|
||||
|
||||
|
||||
|
||||
## [0.1.10] - 2018-08-03
|
||||
### Fixed
|
||||
- Merging `<script>` tags without leading `;` [#55].
|
||||
|
||||
|
||||
## [0.1.9] - 2018-04-29
|
||||
### Fixed
|
||||
- Default minification options safety [#50].
|
||||
|
||||
|
||||
## [0.1.8] - 2018-04-17
|
||||
### Fixed
|
||||
- ES6+ minification [#48].
|
||||
|
||||
|
||||
|
||||
## [0.1.7] - 2018-03-13
|
||||
### Fixed
|
||||
- Update dependencies which also fixes the SVG minification bug [#47].
|
||||
|
||||
|
||||
|
||||
## [0.1.6] - 2017-06-27
|
||||
### Fixed
|
||||
- "Not a function" error [#42].
|
||||
|
||||
|
||||
|
||||
## [0.1.5] - 2016-04-24
|
||||
### Added
|
||||
- Minify SVG [#28].
|
||||
- Merge `<script>` [#19].
|
||||
|
||||
### Changed
|
||||
- Remove redundant `type="submit"` from `<button>` [#31].
|
||||
|
||||
### Fixed
|
||||
- Windows build [#30].
|
||||
|
||||
|
||||
## [0.1.4] - 2016-02-16
|
||||
### Added
|
||||
- Minify JSON.
|
||||
- Merge multiple `<style>` into one.
|
||||
- Collapse boolean attributes.
|
||||
- Remove redundant attributes.
|
||||
- HTML minifiers benchmark [#22].
|
||||
|
||||
### Changed
|
||||
- Expand list of JSON-like mime types [#20].
|
||||
|
||||
|
||||
## [0.1.3] - 2016-02-09
|
||||
### Fixed
|
||||
- Don't alter HTML comments inside not relevant modules [#17].
|
||||
|
||||
|
||||
## [0.1.2] - 2016-02-07
|
||||
### Fixed
|
||||
- Don't remove conditional comments in safe mode [#13].
|
||||
- Downgrade: `String.startsWith -> String.search`.
|
||||
|
||||
|
||||
## [0.1.1] - 2016-01-31
|
||||
### Added
|
||||
- Minify CSS inside `<style>` tags and `style` attributes.
|
||||
- Minify JS inside `<script>` tags and `on*` attributes.
|
||||
|
||||
### Changed
|
||||
- Remove attributes that contains only white spaces.
|
||||
|
||||
|
||||
[2.1.0]: https://github.com/posthtml/htmlnano/compare/2.0.4...2.1.0
|
||||
[2.0.4]: https://github.com/posthtml/htmlnano/compare/2.0.3...2.0.4
|
||||
[2.0.3]: https://github.com/posthtml/htmlnano/compare/2.0.2...2.0.3
|
||||
[2.0.2]: https://github.com/posthtml/htmlnano/compare/2.0.1...2.0.2
|
||||
[2.0.1]: https://github.com/posthtml/htmlnano/compare/2.0.0...2.0.1
|
||||
[2.0.0]: https://github.com/posthtml/htmlnano/compare/1.1.1...2.0.0
|
||||
[1.1.1]: https://github.com/posthtml/htmlnano/compare/1.1.0...1.1.1
|
||||
[1.1.0]: https://github.com/posthtml/htmlnano/compare/1.0.1...1.1.0
|
||||
[1.0.1]: https://github.com/posthtml/htmlnano/compare/1.0.0...1.0.1
|
||||
[1.0.0]: https://github.com/posthtml/htmlnano/compare/0.2.9...1.0.0
|
||||
[0.2.9]: https://github.com/posthtml/htmlnano/compare/0.2.8...0.2.9
|
||||
[0.2.8]: https://github.com/posthtml/htmlnano/compare/0.2.7...0.2.8
|
||||
[0.2.7]: https://github.com/posthtml/htmlnano/compare/0.2.6...0.2.7
|
||||
[0.2.6]: https://github.com/posthtml/htmlnano/compare/0.2.5...0.2.6
|
||||
[0.2.5]: https://github.com/posthtml/htmlnano/compare/0.2.4...0.2.5
|
||||
[0.2.4]: https://github.com/posthtml/htmlnano/compare/0.2.3...0.2.4
|
||||
[0.2.3]: https://github.com/posthtml/htmlnano/compare/0.2.2...0.2.3
|
||||
[0.2.2]: https://github.com/posthtml/htmlnano/compare/0.2.1...0.2.2
|
||||
[0.2.1]: https://github.com/posthtml/htmlnano/compare/0.2.0...0.2.1
|
||||
[0.2.0]: https://github.com/posthtml/htmlnano/compare/0.1.10...0.2.0
|
||||
[0.1.10]: https://github.com/posthtml/htmlnano/compare/0.1.9...0.1.10
|
||||
[0.1.9]: https://github.com/posthtml/htmlnano/compare/0.1.8...0.1.9
|
||||
[0.1.8]: https://github.com/posthtml/htmlnano/compare/0.1.7...0.1.8
|
||||
[0.1.7]: https://github.com/posthtml/htmlnano/compare/0.1.6...0.1.7
|
||||
[0.1.6]: https://github.com/posthtml/htmlnano/compare/0.1.5...0.1.6
|
||||
[0.1.5]: https://github.com/posthtml/htmlnano/compare/0.1.4...0.1.5
|
||||
[0.1.4]: https://github.com/posthtml/htmlnano/compare/0.1.3...0.1.4
|
||||
[0.1.3]: https://github.com/posthtml/htmlnano/compare/0.1.2...0.1.3
|
||||
[0.1.2]: https://github.com/posthtml/htmlnano/compare/0.1.1...0.1.2
|
||||
[0.1.1]: https://github.com/posthtml/htmlnano/compare/0.1.0...0.1.1
|
||||
|
||||
|
||||
[#260]: https://github.com/posthtml/htmlnano/issues/260
|
||||
[#257]: https://github.com/posthtml/htmlnano/issues/257
|
||||
[#220]: https://github.com/posthtml/htmlnano/issues/220
|
||||
[#197]: https://github.com/posthtml/htmlnano/issues/197
|
||||
[#195]: https://github.com/posthtml/htmlnano/issues/195
|
||||
[#185]: https://github.com/posthtml/htmlnano/issues/185
|
||||
[#184]: https://github.com/posthtml/htmlnano/issues/184
|
||||
[#182]: https://github.com/posthtml/htmlnano/issues/182
|
||||
[#180]: https://github.com/posthtml/htmlnano/issues/180
|
||||
[#170]: https://github.com/posthtml/htmlnano/issues/170
|
||||
[#168]: https://github.com/posthtml/htmlnano/issues/168
|
||||
[#165]: https://github.com/posthtml/htmlnano/issues/165
|
||||
[#163]: https://github.com/posthtml/htmlnano/issues/163
|
||||
[#161]: https://github.com/posthtml/htmlnano/issues/161
|
||||
[#159]: https://github.com/posthtml/htmlnano/issues/159
|
||||
[#158]: https://github.com/posthtml/htmlnano/issues/158
|
||||
[#157]: https://github.com/posthtml/htmlnano/issues/157
|
||||
[#156]: https://github.com/posthtml/htmlnano/issues/156
|
||||
[#154]: https://github.com/posthtml/htmlnano/issues/154
|
||||
[#153]: https://github.com/posthtml/htmlnano/issues/153
|
||||
[#145]: https://github.com/posthtml/htmlnano/issues/145
|
||||
[#135]: https://github.com/posthtml/htmlnano/issues/135
|
||||
[#129]: https://github.com/posthtml/htmlnano/issues/129
|
||||
[#127]: https://github.com/posthtml/htmlnano/issues/127
|
||||
[#125]: https://github.com/posthtml/htmlnano/issues/125
|
||||
[#122]: https://github.com/posthtml/htmlnano/issues/122
|
||||
[#120]: https://github.com/posthtml/htmlnano/issues/120
|
||||
[#119]: https://github.com/posthtml/htmlnano/issues/119
|
||||
[#117]: https://github.com/posthtml/htmlnano/issues/117
|
||||
[#116]: https://github.com/posthtml/htmlnano/issues/116
|
||||
[#114]: https://github.com/posthtml/htmlnano/issues/114
|
||||
[#113]: https://github.com/posthtml/htmlnano/issues/113
|
||||
[#112]: https://github.com/posthtml/htmlnano/issues/112
|
||||
[#111]: https://github.com/posthtml/htmlnano/issues/111
|
||||
[#110]: https://github.com/posthtml/htmlnano/issues/110
|
||||
[#108]: https://github.com/posthtml/htmlnano/issues/108
|
||||
[#107]: https://github.com/posthtml/htmlnano/issues/107
|
||||
[#104]: https://github.com/posthtml/htmlnano/issues/104
|
||||
[#102]: https://github.com/posthtml/htmlnano/issues/102
|
||||
[#98]: https://github.com/posthtml/htmlnano/issues/98
|
||||
[#95]: https://github.com/posthtml/htmlnano/issues/95
|
||||
[#94]: https://github.com/posthtml/htmlnano/issues/94
|
||||
[#90]: https://github.com/posthtml/htmlnano/issues/90
|
||||
[#88]: https://github.com/posthtml/htmlnano/issues/88
|
||||
[#84]: https://github.com/posthtml/htmlnano/issues/84
|
||||
[#80]: https://github.com/posthtml/htmlnano/issues/80
|
||||
[#79]: https://github.com/posthtml/htmlnano/issues/79
|
||||
[#78]: https://github.com/posthtml/htmlnano/issues/78
|
||||
[#76]: https://github.com/posthtml/htmlnano/issues/76
|
||||
[#71]: https://github.com/posthtml/htmlnano/issues/71
|
||||
[#67]: https://github.com/posthtml/htmlnano/issues/67
|
||||
[#66]: https://github.com/posthtml/htmlnano/issues/66
|
||||
[#65]: https://github.com/posthtml/htmlnano/issues/65
|
||||
[#64]: https://github.com/posthtml/htmlnano/issues/64
|
||||
[#62]: https://github.com/posthtml/htmlnano/issues/62
|
||||
[#59]: https://github.com/posthtml/htmlnano/issues/59
|
||||
[#55]: https://github.com/posthtml/htmlnano/issues/55
|
||||
[#50]: https://github.com/posthtml/htmlnano/issues/50
|
||||
[#48]: https://github.com/posthtml/htmlnano/issues/48
|
||||
[#47]: https://github.com/posthtml/htmlnano/issues/47
|
||||
[#42]: https://github.com/posthtml/htmlnano/issues/42
|
||||
[#39]: https://github.com/posthtml/htmlnano/issues/39
|
||||
[#36]: https://github.com/posthtml/htmlnano/issues/36
|
||||
[#31]: https://github.com/posthtml/htmlnano/issues/31
|
||||
[#30]: https://github.com/posthtml/htmlnano/issues/30
|
||||
[#28]: https://github.com/posthtml/htmlnano/issues/28
|
||||
[#25]: https://github.com/posthtml/htmlnano/issues/25
|
||||
[#24]: https://github.com/posthtml/htmlnano/issues/24
|
||||
[#22]: https://github.com/posthtml/htmlnano/issues/22
|
||||
[#21]: https://github.com/posthtml/htmlnano/issues/21
|
||||
[#20]: https://github.com/posthtml/htmlnano/issues/20
|
||||
[#19]: https://github.com/posthtml/htmlnano/issues/19
|
||||
[#17]: https://github.com/posthtml/htmlnano/issues/17
|
||||
[#13]: https://github.com/posthtml/htmlnano/issues/13
|
||||
21
webGl/my-threejs-test/node_modules/htmlnano/LICENSE.txt
generated
vendored
Normal file
21
webGl/my-threejs-test/node_modules/htmlnano/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Kirill Maltsev <maltsevkirill@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
22
webGl/my-threejs-test/node_modules/htmlnano/README.md
generated
vendored
Normal file
22
webGl/my-threejs-test/node_modules/htmlnano/README.md
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
# htmlnano
|
||||
[](http://badge.fury.io/js/htmlnano)
|
||||

|
||||
|
||||
Modular HTML minifier, built on top of the [PostHTML](https://github.com/posthtml/posthtml). Inspired by [cssnano](http://cssnano.co/).
|
||||
|
||||
## [Benchmark](https://github.com/maltsev/html-minifiers-benchmark/blob/master/README.md)
|
||||
[html-minifier-terser@6.0.2]: https://www.npmjs.com/package/html-minifier-terser
|
||||
[htmlnano@2.0.0]: https://www.npmjs.com/package/htmlnano
|
||||
|
||||
| Website | Source (KB) | [html-minifier-terser@6.0.2] | [htmlnano@2.0.0] |
|
||||
|---------|------------:|----------------:|-----------:|
|
||||
| [stackoverflow.blog](https://stackoverflow.blog/) | 90 | 82 | 76 |
|
||||
| [github.com](https://github.com/) | 232 | 203 | 173 |
|
||||
| [en.wikipedia.org](https://en.wikipedia.org/wiki/Main_Page) | 81 | 76 | 75 |
|
||||
| [npmjs.com](https://www.npmjs.com/features) | 43 | 40 | 38 |
|
||||
| [tc39.es](https://tc39.es/ecma262/) | 6001 | 5465 | 5459 |
|
||||
| **Avg. minify rate** | 0% | **9%** | **13%** |
|
||||
|
||||
|
||||
## Documentation
|
||||
https://htmlnano.netlify.app
|
||||
33
webGl/my-threejs-test/node_modules/htmlnano/docs/README.md
generated
vendored
Normal file
33
webGl/my-threejs-test/node_modules/htmlnano/docs/README.md
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
# Website
|
||||
|
||||
This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.
|
||||
|
||||
## Installation
|
||||
|
||||
```console
|
||||
yarn install
|
||||
```
|
||||
|
||||
## Local Development
|
||||
|
||||
```console
|
||||
yarn start
|
||||
```
|
||||
|
||||
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
|
||||
|
||||
## Build
|
||||
|
||||
```console
|
||||
yarn build
|
||||
```
|
||||
|
||||
This command generates static content into the `build` directory and can be served using any static contents hosting service.
|
||||
|
||||
## Deployment
|
||||
|
||||
```console
|
||||
GIT_USER=<Your GitHub username> USE_SSH=true yarn deploy
|
||||
```
|
||||
|
||||
If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
|
||||
3
webGl/my-threejs-test/node_modules/htmlnano/docs/babel.config.js
generated
vendored
Normal file
3
webGl/my-threejs-test/node_modules/htmlnano/docs/babel.config.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
|
||||
};
|
||||
22
webGl/my-threejs-test/node_modules/htmlnano/docs/docs/010-introduction.md
generated
vendored
Normal file
22
webGl/my-threejs-test/node_modules/htmlnano/docs/docs/010-introduction.md
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
slug: /
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
Modular HTML minifier, built on top of the [PostHTML](https://github.com/posthtml/posthtml).
|
||||
Inspired by [cssnano](http://cssnano.co/).
|
||||
|
||||
|
||||
## [Benchmark](https://github.com/maltsev/html-minifiers-benchmark/blob/master/README.md)
|
||||
[html-minifier-terser@5.1.1]: https://www.npmjs.com/package/html-minifier-terser
|
||||
[htmlnano@2.0.0]: https://www.npmjs.com/package/htmlnano
|
||||
|
||||
| Website | Source (KB) | [html-minifier-terser@5.1.1] | [htmlnano@2.0.0] |
|
||||
|---------|------------:|----------------:|-----------:|
|
||||
| [stackoverflow.blog](https://stackoverflow.blog/) | 95 | 87 | 82 |
|
||||
| [github.com](https://github.com/) | 210 | 183 | 171 |
|
||||
| [en.wikipedia.org](https://en.wikipedia.org/wiki/Main_Page) | 78 | 72 | 72 |
|
||||
| [npmjs.com](https://www.npmjs.com/features) | 41 | 38 | 36 |
|
||||
| **Avg. minify rate** | 0% | **9%** | **13%** |
|
||||
117
webGl/my-threejs-test/node_modules/htmlnano/docs/docs/020-usage.md
generated
vendored
Normal file
117
webGl/my-threejs-test/node_modules/htmlnano/docs/docs/020-usage.md
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
# Usage
|
||||
## Javascript
|
||||
```js
|
||||
const htmlnano = require('htmlnano');
|
||||
const options = {
|
||||
removeEmptyAttributes: false, // Disable the module "removeEmptyAttributes"
|
||||
collapseWhitespace: 'conservative' // Pass options to the module "collapseWhitespace"
|
||||
};
|
||||
// posthtml, posthtml-render, and posthtml-parse options
|
||||
const postHtmlOptions = {
|
||||
sync: true, // https://github.com/posthtml/posthtml#usage
|
||||
lowerCaseTags: true, // https://github.com/posthtml/posthtml-parser#options
|
||||
quoteAllAttributes: false, // https://github.com/posthtml/posthtml-render#options
|
||||
};
|
||||
|
||||
htmlnano
|
||||
// "preset" arg might be skipped (see "Presets" section below for more info)
|
||||
// "postHtmlOptions" arg might be skipped
|
||||
.process(html, options, preset, postHtmlOptions)
|
||||
.then(function (result) {
|
||||
// result.html is minified
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## PostHTML
|
||||
Just add `htmlnano` as a final plugin:
|
||||
```js
|
||||
const posthtml = require('posthtml');
|
||||
const options = {
|
||||
removeComments: false, // Disable the module "removeComments"
|
||||
collapseWhitespace: 'conservative' // Pass options to the module "collapseWhitespace"
|
||||
};
|
||||
const posthtmlPlugins = [
|
||||
/* other PostHTML plugins */
|
||||
|
||||
require('htmlnano')(options)
|
||||
];
|
||||
|
||||
const posthtmlOptions = {
|
||||
// See PostHTML docs
|
||||
};
|
||||
|
||||
posthtml(posthtmlPlugins)
|
||||
.process(html, posthtmlOptions)
|
||||
.then(function (result) {
|
||||
// result.html is minified
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## Webpack
|
||||
|
||||
```sh
|
||||
npm install html-minimizer-webpack-plugin --save-dev
|
||||
npm install htmlnano --save-dev
|
||||
```
|
||||
|
||||
```js
|
||||
// webpack.config.js
|
||||
const HtmlMinimizerWebpackPlugin = require('html-minimizer-webpack-plugin');
|
||||
const htmlnano = require('htmlnano');
|
||||
|
||||
module.exports = {
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
// For webpack@5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line
|
||||
// `...`,
|
||||
new HtmlMinimizerWebpackPlugin({
|
||||
// Add HtmlMinimizerWebpackPlugin's option here, see https://webpack.js.org/plugins/html-minimizer-webpack-plugin/#options
|
||||
// test: /\.html(\?.*)?$/i,
|
||||
|
||||
// Use htmlnano as HtmlMinimizerWebpackPlugin's minimizer
|
||||
minify: htmlnano.htmlMinimizerWebpackPluginMinify,
|
||||
minimizerOptions: {
|
||||
// Add htmlnano's option here
|
||||
removeComments: false, // Disable the module "removeComments"
|
||||
collapseWhitespace: 'conservative' // Pass options to the module "collapseWhitespace"
|
||||
}
|
||||
})
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Gulp
|
||||
```bash
|
||||
npm i -D gulp-posthtml htmlnano
|
||||
```
|
||||
|
||||
```js
|
||||
const gulp = require('gulp');
|
||||
const posthtml = require('gulp-posthtml');
|
||||
const htmlnano = require('htmlnano');
|
||||
const options = {
|
||||
removeComments: false
|
||||
};
|
||||
|
||||
gulp.task('default', function() {
|
||||
return gulp
|
||||
.src('./index.html')
|
||||
.pipe(posthtml([
|
||||
// Add `htmlnano` as a final plugin
|
||||
htmlnano(options)
|
||||
]))
|
||||
.pipe(gulp.dest('./build'));
|
||||
});
|
||||
```
|
||||
21
webGl/my-threejs-test/node_modules/htmlnano/docs/docs/030-config.md
generated
vendored
Normal file
21
webGl/my-threejs-test/node_modules/htmlnano/docs/docs/030-config.md
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Config
|
||||
|
||||
There are two main ways to configure htmlnano:
|
||||
|
||||
## Passing options to `htmlnano` directly
|
||||
This is the way described above in the examples.
|
||||
|
||||
## Using configuration file
|
||||
Alternatively, you might create a configuration file (e.g., `htmlnanorc.json` or `htmlnanorc.js`) or save options to `package.json` with `htmlnano` key.
|
||||
`htmlnano` uses `cosmiconfig`, so refer to [its documentation](https://github.com/davidtheclark/cosmiconfig/blob/main/README.md) for a more detailed description.
|
||||
|
||||
If you want to specify a preset that way, use `preset` key:
|
||||
|
||||
```json
|
||||
{
|
||||
"preset": "max",
|
||||
}
|
||||
```
|
||||
|
||||
Configuration files have lower precedence than passing options to `htmlnano` directly.
|
||||
So if you use both ways, then the configuration file would be ignored.
|
||||
75
webGl/my-threejs-test/node_modules/htmlnano/docs/docs/040-presets.md
generated
vendored
Normal file
75
webGl/my-threejs-test/node_modules/htmlnano/docs/docs/040-presets.md
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
# Presets
|
||||
|
||||
A preset is just an object with modules config.
|
||||
|
||||
Currently the following presets are available:
|
||||
- [safe](https://github.com/posthtml/htmlnano/blob/master/lib/presets/safe.mjs) — a default preset for minifying a regular HTML in a safe way (without breaking anything)
|
||||
- [ampSafe](https://github.com/posthtml/htmlnano/blob/master/lib/presets/ampSafe.mjs) - same as `safe` preset but for [AMP pages](https://www.ampproject.org/)
|
||||
- [max](https://github.com/posthtml/htmlnano/blob/master/lib/presets/max.mjs) - maximal minification (might break some pages)
|
||||
|
||||
|
||||
You can use them the following way:
|
||||
```js
|
||||
const htmlnano = require('htmlnano');
|
||||
const ampSafePreset = require('htmlnano').presets.ampSafe;
|
||||
const options = {
|
||||
// Your options
|
||||
};
|
||||
|
||||
htmlnano
|
||||
.process(html, options, ampSafePreset)
|
||||
.then(function (result) {
|
||||
// result.html is minified
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
```
|
||||
|
||||
If you skip `preset` argument [`safe`](https://github.com/posthtml/htmlnano/blob/master/lib/presets/safe.mjs) preset would be used by default.
|
||||
|
||||
|
||||
If you'd like to define your very own config without any presets pass an empty object as a preset:
|
||||
```js
|
||||
const htmlnano = require('htmlnano');
|
||||
const options = {
|
||||
// Your options
|
||||
};
|
||||
|
||||
htmlnano
|
||||
.process(html, options, {})
|
||||
.then(function (result) {
|
||||
// result.html is minified
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
You might create also your own presets:
|
||||
```js
|
||||
const htmlnano = require('htmlnano');
|
||||
// Preset for minifying email templates
|
||||
const emailPreset = {
|
||||
mergeStyles: true,
|
||||
minifyCss: {
|
||||
safe: true
|
||||
},
|
||||
};
|
||||
|
||||
const options = {
|
||||
// Some specific options
|
||||
};
|
||||
|
||||
htmlnano
|
||||
.process(html, options, emailPreset)
|
||||
.then(function (result) {
|
||||
// result.html is minified
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
```
|
||||
|
||||
Feel free [to submit a PR](https://github.com/posthtml/htmlnano/issues/new) with your preset if it might be useful for other developers as well.
|
||||
855
webGl/my-threejs-test/node_modules/htmlnano/docs/docs/050-modules.md
generated
vendored
Normal file
855
webGl/my-threejs-test/node_modules/htmlnano/docs/docs/050-modules.md
generated
vendored
Normal file
@@ -0,0 +1,855 @@
|
||||
# Modules
|
||||
|
||||
By default the modules should only perform safe transforms, see the module documentation below for details.
|
||||
You can disable modules by passing `false` as option, and enable them by passing `true`.
|
||||
|
||||
The order in which the modules are documented is also the order in which they are applied.
|
||||
|
||||
## Attributes
|
||||
|
||||
### normalizeAttributeValues
|
||||
|
||||
- Normalize casing of specific attribute values that are case-insensitive (like `form[method]`, `img[img]` and `input[type]`).
|
||||
- Apply [invalid value default](https://html.spec.whatwg.org/#invalid-value-default) attribute to invalid attribute values (like `<input type=foo>` to `<input type=text>`, which can then be minified to `<input>` by `removeRedundantAttributes` module).
|
||||
#### Example
|
||||
|
||||
Source:
|
||||
|
||||
```html
|
||||
<form method="GET"></form>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<form method="get"></form>
|
||||
```
|
||||
|
||||
### removeEmptyAttributes
|
||||
Removes empty [safe-to-remove](https://github.com/posthtml/htmlnano/blob/master/lib/modules/removeEmptyAttributes.mjs) attributes.
|
||||
|
||||
#### Side effects
|
||||
This module could break your styles or JS if you use selectors with attributes:
|
||||
```CSS
|
||||
img[style=""] {
|
||||
margin: 10px;
|
||||
}
|
||||
```
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<img src="foo.jpg" alt="" style="">
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<img src="foo.jpg" alt="">
|
||||
```
|
||||
|
||||
### collapseAttributeWhitespace
|
||||
Collapse redundant white spaces in list-like attributes (`class`, `rel`, `ping`).
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<a class=" content page " style=" display: block; " href=" https://example.com"></a>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<a class="content page" style="display: block;" href="https://example.com"></a>
|
||||
```
|
||||
|
||||
### removeRedundantAttributes
|
||||
Removes redundant attributes from tags if they contain default values:
|
||||
- `method="get"` from `<form>`
|
||||
- `type="text"` from `<input>`
|
||||
- `type="submit"` from `<button>`
|
||||
- `language="javascript"` and `type="text/javascript"` from `<script>`
|
||||
- `charset` from `<script>` if it's an external script
|
||||
- `media="all"` from `<style>` and `<link>`
|
||||
- `type="text/css"` from `<link rel="stylesheet">`
|
||||
|
||||
#### Options
|
||||
This module is disabled by default, change option to true to enable this module.
|
||||
|
||||
#### Side effects
|
||||
This module could break your styles or JS if you use selectors with attributes:
|
||||
```CSS
|
||||
form[method="get"] {
|
||||
color: red;
|
||||
}
|
||||
```
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<form method="get">
|
||||
<input type="text">
|
||||
</form>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<form>
|
||||
<input>
|
||||
</form>
|
||||
```
|
||||
|
||||
### collapseBooleanAttributes
|
||||
|
||||
- Collapses boolean attributes (like `disabled`) to the minimized form.
|
||||
- Collapses empty string value attributes (like `href=""`) to the minimized form.
|
||||
- Collapses [missing value default](https://html.spec.whatwg.org/#missing-value-default) attributes that are empty strings (`audio[preload=auto]` and `video[preload=auto]`) to the minimized form.
|
||||
|
||||
#### Options
|
||||
If your document uses [AMP](https://www.ampproject.org/), set the `amphtml` flag
|
||||
to collapse additonal, AMP-specific boolean attributes:
|
||||
```Json
|
||||
"collapseBooleanAttributes": {
|
||||
"amphtml": true
|
||||
}
|
||||
```
|
||||
|
||||
#### Side effects
|
||||
This module could break your styles or JS if you use selectors with attributes:
|
||||
```CSS
|
||||
button[disabled="disabled"] {
|
||||
color: red;
|
||||
}
|
||||
```
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<button disabled="disabled">click</button>
|
||||
<script defer=""></script>
|
||||
<a href=""></a>
|
||||
<video preload="auto"></video>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<button disabled>click</button>
|
||||
<script defer></script>
|
||||
<a href></a>
|
||||
<video preload></video>
|
||||
```
|
||||
|
||||
### deduplicateAttributeValues
|
||||
Remove duplicate values from list-like attributes (`class`, `rel`, `ping`).
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<div class="sidebar left sidebar"></div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<div class="sidebar left"></div>
|
||||
```
|
||||
|
||||
### minifyUrls
|
||||
Convert absolute URL to relative URL using [relateurl](https://www.npmjs.com/package/relateurl).
|
||||
|
||||
You have to install `relateurl`, `terser` and `srcset` in order to use this feature:
|
||||
|
||||
```bash
|
||||
npm install --save-dev relateurl terser srcset
|
||||
# if you prefer yarn
|
||||
# yarn add --dev relateurl terser srcset
|
||||
# if you prefer pnpm
|
||||
# pnpm install --save-dev relateurl terser srcset
|
||||
```
|
||||
|
||||
#### Options
|
||||
|
||||
The base URL to resolve against. Support `String` & `URL`.
|
||||
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyUrls: 'https://example.com' // Valid configuration
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyUrls: new URL('https://example.com') // Valid configuration
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyUrls: false // The module will be disabled
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyUrls: true // Invalid configuration, the module will be disabled
|
||||
});
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
**Basic Usage**
|
||||
|
||||
Configuration:
|
||||
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyUrls: 'https://example.com'
|
||||
});
|
||||
```
|
||||
|
||||
Source:
|
||||
|
||||
```html
|
||||
<a href="https://example.com/foo/bar/baz">bar</a>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<a href="foo/bar/baz">bar</a>
|
||||
```
|
||||
|
||||
**With sub-directory**
|
||||
|
||||
Configuration:
|
||||
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyUrls: 'https://example.com/foo/baz/'
|
||||
});
|
||||
```
|
||||
|
||||
Source:
|
||||
|
||||
```html
|
||||
<a href="https://example.com/foo/bar">bar</a>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<a href="../bar">bar</a>
|
||||
```
|
||||
|
||||
|
||||
### sortAttributes
|
||||
Sort attributes inside elements.
|
||||
|
||||
The module won't impact the plain-text size of the output. However it will improve the compression ratio of gzip/brotli used in HTTP compression.
|
||||
|
||||
#### Options
|
||||
|
||||
- `alphabetical`: Default option. Sort attributes in alphabetical order.
|
||||
- `frequency`: Sort attributes by frequency.
|
||||
|
||||
#### Example
|
||||
|
||||
**alphabetical**
|
||||
|
||||
Source:
|
||||
```html
|
||||
<input type="text" class="form-control" name="testInput" autofocus="" autocomplete="off" id="testId">
|
||||
```
|
||||
|
||||
Processed:
|
||||
```html
|
||||
<input autocomplete="off" autofocus="" class="form-control" id="testId" name="testInput" type="text">
|
||||
```
|
||||
|
||||
**frequency**
|
||||
|
||||
Source:
|
||||
```html
|
||||
<input type="text" class="form-control" name="testInput" id="testId">
|
||||
<a id="testId" href="#" class="testClass"></a>
|
||||
<img width="20" src="../images/image.png" height="40" alt="image" class="cls" id="id2">
|
||||
```
|
||||
|
||||
Processed:
|
||||
```html
|
||||
<input class="form-control" id="testId" type="text" name="testInput">
|
||||
<a class="testClass" id="testId" href="#"></a>
|
||||
<img class="cls" id="id2" width="20" src="../images/image.png" height="40" alt="image">
|
||||
```
|
||||
|
||||
|
||||
|
||||
### sortAttributesWithLists
|
||||
Sort values in list-like attributes (`class`, `rel`, `ping`).
|
||||
|
||||
The module won't impact the plain-text size of the output. However it will improve the compression ratio of gzip/brotli used in HTTP compression.
|
||||
|
||||
#### Options
|
||||
|
||||
- `alphabetical`: Default option. Sort attribute values in alphabetical order.
|
||||
- `frequency`: Sort attribute values by frequency.
|
||||
|
||||
#### Example
|
||||
|
||||
**alphabetical**
|
||||
|
||||
Source:
|
||||
```html
|
||||
<div class="foo baz bar">click</div>
|
||||
```
|
||||
|
||||
Processed:
|
||||
```html
|
||||
<div class="bar baz foo">click</div>
|
||||
```
|
||||
|
||||
**frequency**
|
||||
|
||||
Source:
|
||||
```html
|
||||
<div class="foo baz bar"></div><div class="bar foo"></div>
|
||||
```
|
||||
|
||||
Processed:
|
||||
```html
|
||||
<div class="foo bar baz"></div><div class="foo bar"></div>
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
#### Options
|
||||
- `conservative` — collapses all redundant white spaces to 1 space (default)
|
||||
- `aggressive` — collapses all whitespaces that are redundant and safe to remove
|
||||
- `all` — collapses all redundant white spaces
|
||||
|
||||
#### Side effects
|
||||
|
||||
*all*
|
||||
`<i>hello</i> <i>world</i>` or `<i>hello</i><br><i>world</i>` after minification will be rendered as `helloworld`.
|
||||
To prevent that use either the default `conservative` option, or the `aggressive` option.
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<div>
|
||||
hello world!
|
||||
<a href="#">answer</a>
|
||||
<style>div { color: red; } </style>
|
||||
<main></main>
|
||||
</div>
|
||||
```
|
||||
|
||||
Minified (with `all`):
|
||||
```html
|
||||
<div>hello world!<a href="#">answer</a><style>div { color: red; } </style><main></main></div>
|
||||
```
|
||||
|
||||
Minified (with `aggressive`):
|
||||
```html
|
||||
<div> hello world! <a href="#">answer</a> <style>div { color: red; } </style><main></main></div>
|
||||
```
|
||||
|
||||
Minified (with `conservative`):
|
||||
```html
|
||||
<div> hello world! <a href="#">answer</a> <style>div { color: red; } </style> <main></main> </div>
|
||||
```
|
||||
|
||||
|
||||
|
||||
## HTML Content
|
||||
|
||||
### collapseWhitespace
|
||||
Collapses redundant white spaces (including new lines). It doesn’t affect white spaces in the elements `<style>`, `<textarea>`, `<script>` and `<pre>`.
|
||||
|
||||
|
||||
### removeComments
|
||||
#### Options
|
||||
- `safe` – removes all HTML comments except the conditional comments and [`<!--noindex--><!--/noindex-->`](https://yandex.com/support/webmaster/controlling-robot/html.xml) (default)
|
||||
- `all` — removes all HTML comments
|
||||
- A `RegExp` — only HTML comments matching the given regexp will be removed.
|
||||
- A `Function` that returns boolean — removes HTML comments that can make the given callback function returns truthy value.
|
||||
|
||||
#### Example
|
||||
|
||||
Source:
|
||||
|
||||
```js
|
||||
{
|
||||
removeComments: 'all'
|
||||
}
|
||||
```
|
||||
|
||||
```html
|
||||
<div><!-- test --></div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<div></div>
|
||||
```
|
||||
|
||||
Source:
|
||||
|
||||
```js
|
||||
{
|
||||
removeComments: /<!--(\/)?noindex-->/
|
||||
}
|
||||
```
|
||||
|
||||
```html
|
||||
<div><!--noindex-->this text will not be indexed<!--/noindex-->Lorem ipsum dolor sit amet<!--more-->Lorem ipsum dolor sit amet</div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<div>this text will not be indexedLorem ipsum dolor sit amet<!--more-->Lorem ipsum dolor sit amet</div>
|
||||
```
|
||||
|
||||
Source:
|
||||
|
||||
```js
|
||||
{
|
||||
removeComments: (comments) => {
|
||||
if (comments.includes('noindex')) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```html
|
||||
<div><!--noindex-->this text will not be indexed<!--/noindex-->Lorem ipsum dolor sit amet<!--more-->Lorem ipsum dolor sit amet</div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<div>this text will not be indexedLorem ipsum dolor sit amet<!--more-->Lorem ipsum dolor sit amet</div>
|
||||
```
|
||||
|
||||
### removeOptionalTags
|
||||
Remove certain tags that can be omitted, see [HTML Standard - 13.1.2.4 Optional tags](https://html.spec.whatwg.org/multipage/syntax.html#optional-tags).
|
||||
|
||||
#### Example
|
||||
|
||||
Source:
|
||||
|
||||
```html
|
||||
<html><head><title>Title</title></head><body><p>Hi</p></body></html>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<title>Title</title><p>Hi</p>
|
||||
```
|
||||
|
||||
#### Notice
|
||||
Due to [the limitation of PostHTML](https://github.com/posthtml/htmlnano/issues/99), htmlnano can't remove only the start tag or the end tag of an element. Currently, htmlnano only supports removing the following optional tags, as htmlnano can remove their start tag and end tag at the same time:
|
||||
|
||||
- `html`
|
||||
- `head`
|
||||
- `body`
|
||||
- `colgroup`
|
||||
- `tbody`
|
||||
|
||||
### removeOptionalTags
|
||||
Remove certain tags that can be omitted, see [HTML Standard - 13.1.2.4 Optional tags](https://html.spec.whatwg.org/multipage/syntax.html#optional-tags).
|
||||
|
||||
#### Example
|
||||
|
||||
Source:
|
||||
|
||||
```html
|
||||
<html><head><title>Title</title></head><body><p>Hi</p></body></html>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<title>Title</title><p>Hi</p>
|
||||
```
|
||||
|
||||
#### Notice
|
||||
Due to [the limitation of PostHTML](https://github.com/posthtml/htmlnano/issues/99), htmlnano can't remove only the start tag or the end tag of an element. Currently, htmlnano only supports removing the following optional tags, as htmlnano can remove their start tag and end tag at the same time:
|
||||
|
||||
- `html`
|
||||
- `head`
|
||||
- `body`
|
||||
- `colgroup`
|
||||
- `tbody`
|
||||
|
||||
### removeAttributeQuotes
|
||||
Remove quotes around attributes when possible, see [HTML Standard - 12.1.2.3 Attributes - Unquoted attribute value syntax](https://html.spec.whatwg.org/multipage/syntax.html#attributes-2).
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<div class="foo" title="hello world"></div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<div class=foo title="hello world"></div>
|
||||
```
|
||||
|
||||
#### Notice
|
||||
The feature is implemented by [posthtml-render's `quoteAllAttributes`](https://github.com/posthtml/posthtml-render#options), which is one of the PostHTML's option. So `removeAttributeQuotes` could be overriden by other PostHTML's plugins and PostHTML's configuration.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
posthtml([
|
||||
htmlnano({
|
||||
removeAttributeQuotes: true
|
||||
})
|
||||
]).process(html, {
|
||||
quoteAllAttributes: true
|
||||
})
|
||||
```
|
||||
|
||||
`removeAttributeQuotes` will not work because PostHTML's `quoteAllAttributes` takes the priority.
|
||||
|
||||
|
||||
## `<style>`, `<script>` and `<svg>` Tags
|
||||
### mergeStyles
|
||||
Merges multiple `<style>` with the same `media` and `type` into one tag.
|
||||
`<style scoped>...</style>` are skipped.
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<style>h1 { color: red }</style>
|
||||
<style media="print">div { color: blue }</style>
|
||||
|
||||
<style type="text/css" media="print">a {}</style>
|
||||
<style>div { font-size: 20px }</style>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<style>h1 { color: red } div { font-size: 20px }</style>
|
||||
<style media="print">div { color: blue } a {}</style>
|
||||
```
|
||||
|
||||
|
||||
### mergeScripts
|
||||
Merge multiple `<script>` with the same attributes (`id, class, type, async, defer`) into one (last) tag.
|
||||
|
||||
#### Side effects
|
||||
It could break your code if the tags with different attributes share the same variable scope.
|
||||
See the example below.
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<script>const foo = 'A:1';</script>
|
||||
<script class="test">foo = 'B:1';</script>
|
||||
<script type="text/javascript">foo = 'A:2';</script>
|
||||
<script defer>foo = 'C:1';</script>
|
||||
<script>foo = 'A:3';</script>
|
||||
<script defer="defer">foo = 'C:2';</script>
|
||||
<script class="test" type="text/javascript">foo = 'B:2';</script>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<script>const foo = 'A:1'; foo = 'A:2'; foo = 'A:3';</script>
|
||||
<script defer="defer">foo = 'C:1'; foo = 'C:2';</script>
|
||||
<script class="test" type="text/javascript">foo = 'B:1'; foo = 'B:2';</script>
|
||||
```
|
||||
|
||||
|
||||
### minifyCss
|
||||
Minifies CSS with [cssnano](http://cssnano.co/) inside `<style>` tags and `style` attributes.
|
||||
|
||||
You have to install `cssnano` and `postcss` in order to use this feature:
|
||||
|
||||
```bash
|
||||
npm install --save-dev cssnano postcss
|
||||
# if you prefer yarn
|
||||
# yarn add --dev cssnano postcss
|
||||
# if you prefer pnpm
|
||||
# pnpm install --save-dev cssnano postcss
|
||||
```
|
||||
|
||||
#### Options
|
||||
See [the documentation of cssnano](http://cssnano.co/docs/optimisations/) for all supported optimizations.
|
||||
By default CSS is minified with preset `default`, which shouldn't have any side-effects.
|
||||
|
||||
To use another preset or disabled some optimizations pass options to `minifyCss` module:
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyCss: {
|
||||
preset: ['default', {
|
||||
discardComments: {
|
||||
removeAll: true,
|
||||
},
|
||||
}]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<div>
|
||||
<style>
|
||||
h1 {
|
||||
margin: 10px 10px 10px 10px;
|
||||
color: #ff0000;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<div>
|
||||
<style>h1{margin:10px;color:red}</style>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
### minifyJs
|
||||
Minifies JS using [Terser](https://github.com/fabiosantoscode/terser) inside `<script>` tags.
|
||||
|
||||
You have to install `terser` in order to use this feature:
|
||||
|
||||
```bash
|
||||
npm install --save-dev terser
|
||||
# if you prefer yarn
|
||||
# yarn add --dev terser
|
||||
# if you prefer pnpm
|
||||
# pnpm install --save-dev terser
|
||||
```
|
||||
|
||||
#### Options
|
||||
See [the documentation of Terser](https://github.com/fabiosantoscode/terser#api-reference) for all supported options.
|
||||
Terser options can be passed directly to the `minifyJs` module:
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyJs: {
|
||||
output: { quote_style: 1 },
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<div>
|
||||
<script>
|
||||
/* comment */
|
||||
const foo = function () {
|
||||
|
||||
};
|
||||
</script>
|
||||
</div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<div>
|
||||
<script>const foo=function(){};</script>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
### minifyJson
|
||||
Minifies JSON inside `<script type="application/json"></script>`.
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<script type="application/json">
|
||||
{
|
||||
"user": "me"
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<script type="application/json">{"user":"me"}</script>
|
||||
```
|
||||
|
||||
|
||||
### minifySvg
|
||||
Minifies SVG inside `<svg>` tags using [SVGO](https://github.com/svg/svgo/).
|
||||
|
||||
#### Options
|
||||
See [the documentation of SVGO](https://github.com/svg/svgo/blob/master/README.md) for all supported options.
|
||||
SVGO options can be passed directly to the `minifySvg` module:
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifySvg: {
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {
|
||||
builtinPluginName: {
|
||||
optionName: 'optionValue'
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<svg version="1.1" baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="100%" height="100%" fill="red" />
|
||||
|
||||
<circle cx="150" cy="100" r="80" fill="green" />
|
||||
|
||||
<text x="150" y="125" font-size="60" text-anchor="middle" fill="white">SVG</text>
|
||||
</svg>`
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<svg baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="red"/><circle cx="150" cy="100" r="80" fill="green"/><text x="150" y="125" font-size="60" text-anchor="middle" fill="#fff">SVG</text></svg>
|
||||
```
|
||||
|
||||
### removeUnusedCss
|
||||
|
||||
Removes unused CSS inside `<style>` tags with either [uncss](https://github.com/uncss/uncss)
|
||||
or [PurgeCSS](https://github.com/FullHuman/purgecss).
|
||||
|
||||
#### With uncss
|
||||
|
||||
You have to install `uncss` in order to use this feature:
|
||||
|
||||
```bash
|
||||
npm install --save-dev uncss
|
||||
# if you prefer yarn
|
||||
# yarn add --dev uncss
|
||||
# if you prefer pnpm
|
||||
# pnpm install --save-dev uncss
|
||||
```
|
||||
|
||||
You can also use a mainted fork [@novaatwarren/uncss](https://www.npmjs.com/package/@novaatwarren/uncss) instead.
|
||||
|
||||
|
||||
##### Options
|
||||
See [the documentation of uncss](https://github.com/uncss/uncss) for all supported options.
|
||||
|
||||
uncss options can be passed directly to the `removeUnusedCss` module:
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
removeUnusedCss: {
|
||||
ignore: ['.do-not-remove']
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
The following uncss options are ignored if passed to the module:
|
||||
|
||||
- `stylesheets`
|
||||
- `ignoreSheets`
|
||||
- `raw`
|
||||
|
||||
#### With PurgeCSS
|
||||
|
||||
Use PurgeCSS instead of uncss by adding `tool: 'purgeCSS'` to the options.
|
||||
|
||||
You have to install `purgecss` in order to use this feature:
|
||||
|
||||
```bash
|
||||
npm install --save-dev purgecss
|
||||
# if you prefer yarn
|
||||
# yarn add --dev purgecss
|
||||
# if you prefer pnpm
|
||||
# pnpm install --save-dev purgecss
|
||||
```
|
||||
|
||||
##### Options
|
||||
|
||||
See [the documentation of PurgeCSS](https://www.purgecss.com) for all supported options.
|
||||
|
||||
PurgeCSS options can be passed directly to the `removeUnusedCss` module:
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
removeUnusedCss: {
|
||||
tool: 'purgeCSS',
|
||||
safelist: ['.do-not-remove']
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
The following PurgeCSS options are ignored if passed to the module:
|
||||
|
||||
- `content`
|
||||
- `css`
|
||||
- `extractors`
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<div class="b">
|
||||
<style>
|
||||
.a {
|
||||
margin: 10px 10px 10px 10px;
|
||||
}
|
||||
.b {
|
||||
color: #ff0000;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
```
|
||||
|
||||
Optimized:
|
||||
```html
|
||||
<div class="b">
|
||||
<style>
|
||||
.b {
|
||||
color: #ff0000;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Miscellaneous
|
||||
|
||||
### custom
|
||||
It's also possible to pass custom modules in the minifier.
|
||||
As a function:
|
||||
```js
|
||||
const options = {
|
||||
custom: function (tree, options) {
|
||||
// Some minification
|
||||
return tree;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Or as a list of functions:
|
||||
```js
|
||||
const options = {
|
||||
custom: [
|
||||
function (tree, options) {
|
||||
// Some minification
|
||||
return tree;
|
||||
},
|
||||
|
||||
function (tree, options) {
|
||||
// Some other minification
|
||||
return tree;
|
||||
}
|
||||
]
|
||||
};
|
||||
```
|
||||
|
||||
htmlnano's options are passed to your custom plugin by the second parameter `options`.
|
||||
16
webGl/my-threejs-test/node_modules/htmlnano/docs/docs/060-contribute.md
generated
vendored
Normal file
16
webGl/my-threejs-test/node_modules/htmlnano/docs/docs/060-contribute.md
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
# Contribute
|
||||
|
||||
Since the minifier is modular, it's very easy to add new modules:
|
||||
|
||||
1. Create a ES6-file inside `lib/modules/` with a function that does some minification. For example you can check [`lib/modules/example.mjs`](https://github.com/posthtml/htmlnano/blob/master/lib/modules/example.mjs).
|
||||
|
||||
2. Add the module's name into one of those [presets](https://github.com/posthtml/htmlnano/tree/master/lib/presets). You can choose either `ampSafe`, `max`, or `safe`.
|
||||
|
||||
3. Create a JS-file inside `test/modules/` with some unit-tests.
|
||||
|
||||
4. Describe your module in the section "[Modules](https://github.com/posthtml/htmlnano/blob/master/README.md#modules)".
|
||||
|
||||
5. Send me a pull request.
|
||||
|
||||
Other types of contribution (bug fixes, documentation improves, etc) are also welcome!
|
||||
Would like to contribute, but don't have any ideas what to do? Check out [our issues](https://github.com/posthtml/htmlnano/labels/help%20wanted).
|
||||
65
webGl/my-threejs-test/node_modules/htmlnano/docs/docusaurus.config.js
generated
vendored
Normal file
65
webGl/my-threejs-test/node_modules/htmlnano/docs/docusaurus.config.js
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
const lightCodeTheme = require('prism-react-renderer/themes/github');
|
||||
const darkCodeTheme = require('prism-react-renderer/themes/dracula');
|
||||
|
||||
/** @type {import('@docusaurus/types').DocusaurusConfig} */
|
||||
module.exports = {
|
||||
title: 'htmlnano',
|
||||
tagline: 'Modular HTML minifier',
|
||||
url: 'https://htmlnano.netlify.app',
|
||||
favicon: 'favicon.ico',
|
||||
baseUrl: '/',
|
||||
onBrokenLinks: 'throw',
|
||||
onBrokenMarkdownLinks: 'warn',
|
||||
organizationName: 'posthtml',
|
||||
projectName: 'htmlnano',
|
||||
trailingSlash: false,
|
||||
plugins: ['docusaurus-plugin-goatcounter'],
|
||||
themeConfig: {
|
||||
navbar: {
|
||||
title: 'htmlnano',
|
||||
items: [
|
||||
{
|
||||
type: 'docsVersionDropdown',
|
||||
position: 'right',
|
||||
dropdownActiveClassDisabled: true,
|
||||
},
|
||||
{
|
||||
href: 'https://github.com/posthtml/htmlnano',
|
||||
label: 'GitHub',
|
||||
position: 'right',
|
||||
},
|
||||
],
|
||||
},
|
||||
prism: {
|
||||
theme: lightCodeTheme,
|
||||
darkTheme: darkCodeTheme,
|
||||
},
|
||||
goatcounter: {
|
||||
code: 'htmlnano',
|
||||
},
|
||||
},
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
sidebarPath: require.resolve('./sidebars.js'),
|
||||
routeBasePath: '/',
|
||||
editUrl: 'https://github.com/posthtml/htmlnano/edit/master/docs/',
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
const algoliaConfig = {
|
||||
appId: process.env.ALGOLIA_APP_ID,
|
||||
apiKey: process.env.ALGOLIA_API_KEY,
|
||||
indexName: 'htmlnano',
|
||||
contextualSearch: true,
|
||||
};
|
||||
|
||||
if (algoliaConfig.apiKey) {
|
||||
module.exports.themeConfig.algolia = algoliaConfig;
|
||||
}
|
||||
4
webGl/my-threejs-test/node_modules/htmlnano/docs/netlify.toml
generated
vendored
Normal file
4
webGl/my-threejs-test/node_modules/htmlnano/docs/netlify.toml
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
[build]
|
||||
base = "docs/"
|
||||
publish = "build/"
|
||||
command = "npm run build"
|
||||
21612
webGl/my-threejs-test/node_modules/htmlnano/docs/package-lock.json
generated
vendored
Normal file
21612
webGl/my-threejs-test/node_modules/htmlnano/docs/package-lock.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
40
webGl/my-threejs-test/node_modules/htmlnano/docs/package.json
generated
vendored
Normal file
40
webGl/my-threejs-test/node_modules/htmlnano/docs/package.json
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "htmlnano-docs",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
"start": "docusaurus start",
|
||||
"build": "docusaurus build",
|
||||
"swizzle": "docusaurus swizzle",
|
||||
"deploy": "docusaurus deploy",
|
||||
"clear": "docusaurus clear",
|
||||
"serve": "docusaurus serve",
|
||||
"write-translations": "docusaurus write-translations",
|
||||
"write-heading-ids": "docusaurus write-heading-ids"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.2.0",
|
||||
"@docusaurus/preset-classic": "2.2.0",
|
||||
"@mdx-js/react": "^1.6.21",
|
||||
"@svgr/webpack": "^6.5.1",
|
||||
"clsx": "^1.1.1",
|
||||
"docusaurus-plugin-goatcounter": "^2.0.1",
|
||||
"file-loader": "^6.2.0",
|
||||
"prism-react-renderer": "^1.2.1",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1",
|
||||
"url-loader": "^4.1.1"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.5%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
26
webGl/my-threejs-test/node_modules/htmlnano/docs/sidebars.js
generated
vendored
Normal file
26
webGl/my-threejs-test/node_modules/htmlnano/docs/sidebars.js
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Creating a sidebar enables you to:
|
||||
- create an ordered group of docs
|
||||
- render a sidebar for each doc of that group
|
||||
- provide next/previous navigation
|
||||
|
||||
The sidebars can be generated from the filesystem, or explicitly defined here.
|
||||
|
||||
Create as many sidebars as you want.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// By default, Docusaurus generates a sidebar from the docs folder structure
|
||||
tutorialSidebar: [{type: 'autogenerated', dirName: '.'}],
|
||||
|
||||
// But you can create a sidebar manually
|
||||
/*
|
||||
tutorialSidebar: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Tutorial',
|
||||
items: ['hello'],
|
||||
},
|
||||
],
|
||||
*/
|
||||
};
|
||||
22
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-1.1.1/010-introduction.md
generated
vendored
Normal file
22
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-1.1.1/010-introduction.md
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
slug: /
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
Modular HTML minifier, built on top of the [PostHTML](https://github.com/posthtml/posthtml).
|
||||
Inspired by [cssnano](http://cssnano.co/).
|
||||
|
||||
|
||||
## [Benchmark](https://github.com/maltsev/html-minifiers-benchmark/blob/master/README.md)
|
||||
[html-minifier-terser@5.1.1]: https://www.npmjs.com/package/html-minifier-terser
|
||||
[htmlnano@1.1.1]: https://www.npmjs.com/package/htmlnano
|
||||
|
||||
| Website | Source (KB) | [html-minifier-terser@5.1.1] | [htmlnano@1.1.1] |
|
||||
|---------|------------:|----------------:|-----------:|
|
||||
| [stackoverflow.blog](https://stackoverflow.blog/) | 95 | 87 | 82 |
|
||||
| [github.com](https://github.com/) | 210 | 183 | 171 |
|
||||
| [en.wikipedia.org](https://en.wikipedia.org/wiki/Main_Page) | 78 | 72 | 72 |
|
||||
| [npmjs.com](https://www.npmjs.com/features) | 41 | 38 | 36 |
|
||||
| **Avg. minify rate** | 0% | **9%** | **13%** |
|
||||
77
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-1.1.1/020-usage.md
generated
vendored
Normal file
77
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-1.1.1/020-usage.md
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
# Usage
|
||||
|
||||
## Gulp
|
||||
```bash
|
||||
npm install --save-dev gulp-htmlnano
|
||||
```
|
||||
|
||||
```js
|
||||
const gulp = require('gulp');
|
||||
const htmlnano = require('gulp-htmlnano');
|
||||
const options = {
|
||||
removeComments: false
|
||||
};
|
||||
|
||||
gulp.task('default', function() {
|
||||
return gulp
|
||||
.src('./index.html')
|
||||
.pipe(htmlnano(options))
|
||||
.pipe(gulp.dest('./build'));
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## Javascript
|
||||
```js
|
||||
const htmlnano = require('htmlnano');
|
||||
const options = {
|
||||
removeEmptyAttributes: false, // Disable the module "removeEmptyAttributes"
|
||||
collapseWhitespace: 'conservative' // Pass options to the module "collapseWhitespace"
|
||||
};
|
||||
// posthtml, posthtml-render, and posthtml-parse options
|
||||
const postHtmlOptions = {
|
||||
sync: true, // https://github.com/posthtml/posthtml#usage
|
||||
lowerCaseTags: true, // https://github.com/posthtml/posthtml-parser#options
|
||||
quoteAllAttributes: false, // https://github.com/posthtml/posthtml-render#options
|
||||
};
|
||||
|
||||
htmlnano
|
||||
// "preset" arg might be skipped (see "Presets" section below for more info)
|
||||
// "postHtmlOptions" arg might be skipped
|
||||
.process(html, options, preset, postHtmlOptions)
|
||||
.then(function (result) {
|
||||
// result.html is minified
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## PostHTML
|
||||
Just add `htmlnano` as a final plugin:
|
||||
```js
|
||||
const posthtml = require('posthtml');
|
||||
const options = {
|
||||
removeComments: false, // Disable the module "removeComments"
|
||||
collapseWhitespace: 'conservative' // Pass options to the module "collapseWhitespace"
|
||||
};
|
||||
const posthtmlPlugins = [
|
||||
/* other PostHTML plugins */
|
||||
|
||||
require('htmlnano')(options)
|
||||
];
|
||||
|
||||
const posthtmlOptions = {
|
||||
// See PostHTML docs
|
||||
};
|
||||
|
||||
posthtml(posthtmlPlugins)
|
||||
.process(html, posthtmlOptions)
|
||||
.then(function (result) {
|
||||
// result.html is minified
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
```
|
||||
21
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-1.1.1/030-config.md
generated
vendored
Normal file
21
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-1.1.1/030-config.md
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Config
|
||||
|
||||
There are two main ways to configure htmlnano:
|
||||
|
||||
## Passing options to `htmlnano` directly
|
||||
This is the way described above in the examples.
|
||||
|
||||
## Using configuration file
|
||||
Alternatively, you might create a configuration file (e.g., `htmlnanorc.json` or `htmlnanorc.js`) or save options to `package.json` with `htmlnano` key.
|
||||
`htmlnano` uses `cosmiconfig`, so refer to [its documentation](https://github.com/davidtheclark/cosmiconfig/blob/main/README.md) for a more detailed description.
|
||||
|
||||
If you want to specify a preset that way, use `preset` key:
|
||||
|
||||
```json
|
||||
{
|
||||
"preset": "max",
|
||||
}
|
||||
```
|
||||
|
||||
Configuration files have lower precedence than passing options to `htmlnano` directly.
|
||||
So if you use both ways, then the configuration file would be ignored.
|
||||
75
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-1.1.1/040-presets.md
generated
vendored
Normal file
75
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-1.1.1/040-presets.md
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
# Presets
|
||||
|
||||
A preset is just an object with modules config.
|
||||
|
||||
Currently the following presets are available:
|
||||
- [safe](https://github.com/posthtml/htmlnano/blob/master/lib/presets/safe.mjs) — a default preset for minifying a regular HTML in a safe way (without breaking anything)
|
||||
- [ampSafe](https://github.com/posthtml/htmlnano/blob/master/lib/presets/ampSafe.mjs) - same as `safe` preset but for [AMP pages](https://www.ampproject.org/)
|
||||
- [max](https://github.com/posthtml/htmlnano/blob/master/lib/presets/max.mjs) - maximal minification (might break some pages)
|
||||
|
||||
|
||||
You can use them the following way:
|
||||
```js
|
||||
const htmlnano = require('htmlnano');
|
||||
const ampSafePreset = require('htmlnano').presets.ampSafe;
|
||||
const options = {
|
||||
// Your options
|
||||
};
|
||||
|
||||
htmlnano
|
||||
.process(html, options, ampSafePreset)
|
||||
.then(function (result) {
|
||||
// result.html is minified
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
```
|
||||
|
||||
If you skip `preset` argument [`safe`](https://github.com/posthtml/htmlnano/blob/master/lib/presets/safe.mjs) preset would be used by default.
|
||||
|
||||
|
||||
If you'd like to define your very own config without any presets pass an empty object as a preset:
|
||||
```js
|
||||
const htmlnano = require('htmlnano');
|
||||
const options = {
|
||||
// Your options
|
||||
};
|
||||
|
||||
htmlnano
|
||||
.process(html, options, {})
|
||||
.then(function (result) {
|
||||
// result.html is minified
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
You might create also your own presets:
|
||||
```js
|
||||
const htmlnano = require('htmlnano');
|
||||
// Preset for minifying email templates
|
||||
const emailPreset = {
|
||||
mergeStyles: true,
|
||||
minifyCss: {
|
||||
safe: true
|
||||
},
|
||||
};
|
||||
|
||||
const options = {
|
||||
// Some specific options
|
||||
};
|
||||
|
||||
htmlnano
|
||||
.process(html, options, emailPreset)
|
||||
.then(function (result) {
|
||||
// result.html is minified
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
```
|
||||
|
||||
Feel free [to submit a PR](https://github.com/posthtml/htmlnano/issues/new) with your preset if it might be useful for other developers as well.
|
||||
785
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-1.1.1/050-modules.md
generated
vendored
Normal file
785
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-1.1.1/050-modules.md
generated
vendored
Normal file
@@ -0,0 +1,785 @@
|
||||
# Modules
|
||||
|
||||
By default the modules should only perform safe transforms, see the module documentation below for details.
|
||||
You can disable modules by passing `false` as option, and enable them by passing `true`.
|
||||
|
||||
|
||||
### collapseAttributeWhitespace
|
||||
Collapse redundant white spaces in list-like attributes (`class`, `rel`, `ping`).
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<a class=" content page " style=" display: block; " href=" https://example.com"></a>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<a class="content page" style="display: block;" href="https://example.com"></a>
|
||||
```
|
||||
|
||||
|
||||
|
||||
### collapseWhitespace
|
||||
Collapses redundant white spaces (including new lines). It doesn’t affect white spaces in the elements `<style>`, `<textarea>`, `<script>` and `<pre>`.
|
||||
|
||||
#### Options
|
||||
- `conservative` — collapses all redundant white spaces to 1 space (default)
|
||||
- `aggressive` — collapses all whitespaces that are redundant and safe to remove
|
||||
- `all` — collapses all redundant white spaces
|
||||
|
||||
#### Side effects
|
||||
|
||||
*all*
|
||||
`<i>hello</i> <i>world</i>` or `<i>hello</i><br><i>world</i>` after minification will be rendered as `helloworld`.
|
||||
To prevent that use either the default `conservative` option, or the `aggressive` option.
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<div>
|
||||
hello world!
|
||||
<a href="#">answer</a>
|
||||
<style>div { color: red; } </style>
|
||||
<main></main>
|
||||
</div>
|
||||
```
|
||||
|
||||
Minified (with `all`):
|
||||
```html
|
||||
<div>hello world!<a href="#">answer</a><style>div { color: red; } </style><main></main></div>
|
||||
```
|
||||
|
||||
Minified (with `aggressive`):
|
||||
```html
|
||||
<div> hello world! <a href="#">answer</a> <style>div { color: red; } </style><main></main></div>
|
||||
```
|
||||
|
||||
Minified (with `conservative`):
|
||||
```html
|
||||
<div> hello world! <a href="#">answer</a> <style>div { color: red; } </style> <main></main> </div>
|
||||
```
|
||||
|
||||
|
||||
### deduplicateAttributeValues
|
||||
Remove duplicate values from list-like attributes (`class`, `rel`, `ping`).
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<div class="sidebar left sidebar"></div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<div class="sidebar left"></div>
|
||||
```
|
||||
|
||||
|
||||
### removeComments
|
||||
#### Options
|
||||
- `safe` – removes all HTML comments except the conditional comments and [`<!--noindex--><!--/noindex-->`](https://yandex.com/support/webmaster/controlling-robot/html.xml) (default)
|
||||
- `all` — removes all HTML comments
|
||||
- A `RegExp` — only HTML comments matching the given regexp will be removed.
|
||||
- A `Function` that returns boolean — removes HTML comments that can make the given callback function returns truthy value.
|
||||
|
||||
#### Example
|
||||
|
||||
Source:
|
||||
|
||||
```js
|
||||
{
|
||||
removeComments: 'all'
|
||||
}
|
||||
```
|
||||
|
||||
```html
|
||||
<div><!-- test --></div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<div></div>
|
||||
```
|
||||
|
||||
Source:
|
||||
|
||||
```js
|
||||
{
|
||||
removeComments: /<!--(\/)?noindex-->/
|
||||
}
|
||||
```
|
||||
|
||||
```html
|
||||
<div><!--noindex-->this text will not be indexed<!--/noindex-->Lorem ipsum dolor sit amet<!--more-->Lorem ipsum dolor sit amet</div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<div>this text will not be indexedLorem ipsum dolor sit amet<!--more-->Lorem ipsum dolor sit amet</div>
|
||||
```
|
||||
|
||||
Source:
|
||||
|
||||
```js
|
||||
{
|
||||
removeComments: (comments) => {
|
||||
if (comments.includes('noindex')) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```html
|
||||
<div><!--noindex-->this text will not be indexed<!--/noindex-->Lorem ipsum dolor sit amet<!--more-->Lorem ipsum dolor sit amet</div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<div>this text will not be indexedLorem ipsum dolor sit amet<!--more-->Lorem ipsum dolor sit amet</div>
|
||||
```
|
||||
|
||||
|
||||
### removeEmptyAttributes
|
||||
Removes empty [safe-to-remove](https://github.com/posthtml/htmlnano/blob/master/lib/modules/removeEmptyAttributes.mjs) attributes.
|
||||
|
||||
#### Side effects
|
||||
This module could break your styles or JS if you use selectors with attributes:
|
||||
```CSS
|
||||
img[style=""] {
|
||||
margin: 10px;
|
||||
}
|
||||
```
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<img src="foo.jpg" alt="" style="">
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<img src="foo.jpg" alt="">
|
||||
```
|
||||
|
||||
### removeAttributeQuotes
|
||||
Remove quotes around attributes when possible, see [HTML Standard - 12.1.2.3 Attributes - Unquoted attribute value syntax](https://html.spec.whatwg.org/multipage/syntax.html#attributes-2).
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<div class="foo" title="hello world"></div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<div class=foo title="hello world"></div>
|
||||
```
|
||||
|
||||
#### Notice
|
||||
The feature is implemented by [posthtml-render's `quoteAllAttributes`](https://github.com/posthtml/posthtml-render#options), which is one of the PostHTML's option. So `removeAttributeQuotes` could be overriden by other PostHTML's plugins and PostHTML's configuration.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
posthtml([
|
||||
htmlnano({
|
||||
removeAttributeQuotes: true
|
||||
})
|
||||
]).process(html, {
|
||||
quoteAllAttributes: true
|
||||
})
|
||||
```
|
||||
|
||||
`removeAttributeQuotes` will not work because PostHTML's `quoteAllAttributes` takes the priority.
|
||||
|
||||
### removeUnusedCss
|
||||
|
||||
Removes unused CSS inside `<style>` tags with either [uncss](https://github.com/uncss/uncss)
|
||||
or [PurgeCSS](https://github.com/FullHuman/purgecss).
|
||||
|
||||
#### With uncss
|
||||
|
||||
##### Options
|
||||
See [the documentation of uncss](https://github.com/uncss/uncss) for all supported options.
|
||||
|
||||
uncss options can be passed directly to the `removeUnusedCss` module:
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
removeUnusedCss: {
|
||||
ignore: ['.do-not-remove']
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
The following uncss options are ignored if passed to the module:
|
||||
|
||||
- `stylesheets`
|
||||
- `ignoreSheets`
|
||||
- `raw`
|
||||
|
||||
#### With PurgeCSS
|
||||
|
||||
Use PurgeCSS instead of uncss by adding `tool: 'purgeCSS'` to the options.
|
||||
|
||||
##### Options
|
||||
|
||||
See [the documentation of PurgeCSS](https://www.purgecss.com) for all supported options.
|
||||
|
||||
PurgeCSS options can be passed directly to the `removeUnusedCss` module:
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
removeUnusedCss: {
|
||||
tool: 'purgeCSS',
|
||||
safelist: ['.do-not-remove']
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
The following PurgeCSS options are ignored if passed to the module:
|
||||
|
||||
- `content`
|
||||
- `css`
|
||||
- `extractors`
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<div class="b">
|
||||
<style>
|
||||
.a {
|
||||
margin: 10px 10px 10px 10px;
|
||||
}
|
||||
.b {
|
||||
color: #ff0000;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
```
|
||||
|
||||
Optimized:
|
||||
```html
|
||||
<div class="b">
|
||||
<style>
|
||||
.b {
|
||||
color: #ff0000;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
### minifyCss
|
||||
Minifies CSS with [cssnano](http://cssnano.co/) inside `<style>` tags and `style` attributes.
|
||||
|
||||
#### Options
|
||||
See [the documentation of cssnano](http://cssnano.co/optimisations/) for all supported optimizations.
|
||||
By default CSS is minified with preset `default`, which shouldn't have any side-effects.
|
||||
|
||||
To use another preset or disabled some optimizations pass options to `minifyCss` module:
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyCss: {
|
||||
preset: ['default', {
|
||||
discardComments: {
|
||||
removeAll: true,
|
||||
},
|
||||
}]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<div>
|
||||
<style>
|
||||
h1 {
|
||||
margin: 10px 10px 10px 10px;
|
||||
color: #ff0000;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<div>
|
||||
<style>h1{margin:10px;color:red}</style>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
### minifyJs
|
||||
Minifies JS using [Terser](https://github.com/fabiosantoscode/terser) inside `<script>` tags.
|
||||
|
||||
#### Options
|
||||
See [the documentation of Terser](https://github.com/fabiosantoscode/terser#api-reference) for all supported options.
|
||||
Terser options can be passed directly to the `minifyJs` module:
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyJs: {
|
||||
output: { quote_style: 1 },
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<div>
|
||||
<script>
|
||||
/* comment */
|
||||
const foo = function () {
|
||||
|
||||
};
|
||||
</script>
|
||||
</div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<div>
|
||||
<script>const foo=function(){};</script>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
### minifyJson
|
||||
Minifies JSON inside `<script type="application/json"></script>`.
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<script type="application/json">
|
||||
{
|
||||
"user": "me"
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<script type="application/json">{"user":"me"}</script>
|
||||
```
|
||||
|
||||
|
||||
### minifySvg
|
||||
Minifies SVG inside `<svg>` tags using [SVGO](https://github.com/svg/svgo/).
|
||||
|
||||
#### Options
|
||||
See [the documentation of SVGO](https://github.com/svg/svgo/blob/master/README.md) for all supported options.
|
||||
SVGO options can be passed directly to the `minifySvg` module:
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifySvg: {
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {
|
||||
builtinPluginName: {
|
||||
optionName: 'optionValue'
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<svg version="1.1" baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="100%" height="100%" fill="red" />
|
||||
|
||||
<circle cx="150" cy="100" r="80" fill="green" />
|
||||
|
||||
<text x="150" y="125" font-size="60" text-anchor="middle" fill="white">SVG</text>
|
||||
</svg>`
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<svg baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="red"/><circle cx="150" cy="100" r="80" fill="green"/><text x="150" y="125" font-size="60" text-anchor="middle" fill="#fff">SVG</text></svg>
|
||||
```
|
||||
|
||||
### minifyConditionalComments
|
||||
|
||||
Minify content inside conditional comments.
|
||||
|
||||
#### Example
|
||||
|
||||
Source:
|
||||
|
||||
```html
|
||||
<!--[if lte IE 7]>
|
||||
<style type="text/css">
|
||||
.title {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
<![endif]-->
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<!--[if lte IE 7]><style>.title{color:red}</style><![endif]-->
|
||||
```
|
||||
|
||||
### removeRedundantAttributes
|
||||
Removes redundant attributes from tags if they contain default values:
|
||||
- `method="get"` from `<form>`
|
||||
- `type="text"` from `<input>`
|
||||
- `type="submit"` from `<button>`
|
||||
- `language="javascript"` and `type="text/javascript"` from `<script>`
|
||||
- `charset` from `<script>` if it's an external script
|
||||
- `media="all"` from `<style>` and `<link>`
|
||||
- `type="text/css"` from `<link rel="stylesheet">`
|
||||
|
||||
#### Options
|
||||
This module is disabled by default, change option to true to enable this module.
|
||||
|
||||
#### Side effects
|
||||
This module could break your styles or JS if you use selectors with attributes:
|
||||
```CSS
|
||||
form[method="get"] {
|
||||
color: red;
|
||||
}
|
||||
```
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<form method="get">
|
||||
<input type="text">
|
||||
</form>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<form>
|
||||
<input>
|
||||
</form>
|
||||
```
|
||||
|
||||
|
||||
### collapseBooleanAttributes
|
||||
Collapses boolean attributes (like `disabled`) to the minimized form.
|
||||
|
||||
#### Options
|
||||
If your document uses [AMP](https://www.ampproject.org/), set the `amphtml` flag
|
||||
to collapse additonal, AMP-specific boolean attributes:
|
||||
```Json
|
||||
"collapseBooleanAttributes": {
|
||||
"amphtml": true
|
||||
}
|
||||
```
|
||||
|
||||
#### Side effects
|
||||
This module could break your styles or JS if you use selectors with attributes:
|
||||
```CSS
|
||||
button[disabled="disabled"] {
|
||||
color: red;
|
||||
}
|
||||
```
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<button disabled="disabled">click</button>
|
||||
<script defer=""></script>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<button disabled>click</button>
|
||||
<script defer></script>
|
||||
```
|
||||
|
||||
|
||||
### mergeStyles
|
||||
Merges multiple `<style>` with the same `media` and `type` into one tag.
|
||||
`<style scoped>...</style>` are skipped.
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<style>h1 { color: red }</style>
|
||||
<style media="print">div { color: blue }</style>
|
||||
|
||||
<style type="text/css" media="print">a {}</style>
|
||||
<style>div { font-size: 20px }</style>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<style>h1 { color: red } div { font-size: 20px }</style>
|
||||
<style media="print">div { color: blue } a {}</style>
|
||||
```
|
||||
|
||||
|
||||
### mergeScripts
|
||||
Merge multiple `<script>` with the same attributes (`id, class, type, async, defer`) into one (last) tag.
|
||||
|
||||
#### Side effects
|
||||
It could break your code if the tags with different attributes share the same variable scope.
|
||||
See the example below.
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<script>const foo = 'A:1';</script>
|
||||
<script class="test">foo = 'B:1';</script>
|
||||
<script type="text/javascript">foo = 'A:2';</script>
|
||||
<script defer>foo = 'C:1';</script>
|
||||
<script>foo = 'A:3';</script>
|
||||
<script defer="defer">foo = 'C:2';</script>
|
||||
<script class="test" type="text/javascript">foo = 'B:2';</script>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<script>const foo = 'A:1'; foo = 'A:2'; foo = 'A:3';</script>
|
||||
<script defer="defer">foo = 'C:1'; foo = 'C:2';</script>
|
||||
<script class="test" type="text/javascript">foo = 'B:1'; foo = 'B:2';</script>
|
||||
```
|
||||
|
||||
|
||||
### custom
|
||||
It's also possible to pass custom modules in the minifier.
|
||||
As a function:
|
||||
```js
|
||||
const options = {
|
||||
custom: function (tree, options) {
|
||||
// Some minification
|
||||
return tree;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Or as a list of functions:
|
||||
```js
|
||||
const options = {
|
||||
custom: [
|
||||
function (tree, options) {
|
||||
// Some minification
|
||||
return tree;
|
||||
},
|
||||
|
||||
function (tree, options) {
|
||||
// Some other minification
|
||||
return tree;
|
||||
}
|
||||
]
|
||||
};
|
||||
```
|
||||
|
||||
`options` is an object with all options that were passed to the plugin.
|
||||
|
||||
### sortAttributesWithLists
|
||||
Sort values in list-like attributes (`class`, `rel`, `ping`).
|
||||
|
||||
The module won't impact the plain-text size of the output. However it will improve the compression ratio of gzip/brotli used in HTTP compression.
|
||||
|
||||
#### Options
|
||||
|
||||
- `alphabetical`: Default option. Sort attribute values in alphabetical order.
|
||||
- `frequency`: Sort attribute values by frequency.
|
||||
|
||||
#### Example
|
||||
|
||||
**alphabetical**
|
||||
|
||||
Source:
|
||||
```html
|
||||
<div class="foo baz bar">click</div>
|
||||
```
|
||||
|
||||
Processed:
|
||||
```html
|
||||
<div class="bar baz foo">click</div>
|
||||
```
|
||||
|
||||
**frequency**
|
||||
|
||||
Source:
|
||||
```html
|
||||
<div class="foo baz bar"></div><div class="bar foo"></div>
|
||||
```
|
||||
|
||||
Processed:
|
||||
```html
|
||||
<div class="foo bar baz"></div><div class="foo bar"></div>
|
||||
```
|
||||
|
||||
### sortAttributes
|
||||
Sort attributes inside elements.
|
||||
|
||||
The module won't impact the plain-text size of the output. However it will improve the compression ratio of gzip/brotli used in HTTP compression.
|
||||
|
||||
#### Options
|
||||
|
||||
- `alphabetical`: Default option. Sort attributes in alphabetical order.
|
||||
- `frequency`: Sort attributes by frequency.
|
||||
|
||||
#### Example
|
||||
|
||||
**alphabetical**
|
||||
|
||||
Source:
|
||||
```html
|
||||
<input type="text" class="form-control" name="testInput" autofocus="" autocomplete="off" id="testId">
|
||||
```
|
||||
|
||||
Processed:
|
||||
```html
|
||||
<input autocomplete="off" autofocus="" class="form-control" id="testId" name="testInput" type="text">
|
||||
```
|
||||
|
||||
**frequency**
|
||||
|
||||
Source:
|
||||
```html
|
||||
<input type="text" class="form-control" name="testInput" id="testId">
|
||||
<a id="testId" href="#" class="testClass"></a>
|
||||
<img width="20" src="../images/image.png" height="40" alt="image" class="cls" id="id2">
|
||||
```
|
||||
|
||||
Processed:
|
||||
```html
|
||||
<input class="form-control" id="testId" type="text" name="testInput">
|
||||
<a class="testClass" id="testId" href="#"></a>
|
||||
<img class="cls" id="id2" width="20" src="../images/image.png" height="40" alt="image">
|
||||
```
|
||||
|
||||
### minifyUrls
|
||||
Convert absolute URL to relative URL using [relateurl](https://www.npmjs.com/package/relateurl).
|
||||
|
||||
#### Options
|
||||
|
||||
The base URL to resolve against. Support `String` & `URL`.
|
||||
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyUrls: 'https://example.com' // Valid configuration
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyUrls: new URL('https://example.com') // Valid configuration
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyUrls: false // The module will be disabled
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyUrls: true // Invalid configuration, the module will be disabled
|
||||
});
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
**Basic Usage**
|
||||
|
||||
Configuration:
|
||||
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyUrls: 'https://example.com'
|
||||
});
|
||||
```
|
||||
|
||||
Source:
|
||||
|
||||
```html
|
||||
<a href="https://example.com/foo/bar/baz">bar</a>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<a href="foo/bar/baz">bar</a>
|
||||
```
|
||||
|
||||
**With sub-directory**
|
||||
|
||||
Configuration:
|
||||
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyUrls: 'https://example.com/foo/baz/'
|
||||
});
|
||||
```
|
||||
|
||||
Source:
|
||||
|
||||
```html
|
||||
<a href="https://example.com/foo/bar">bar</a>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<a href="../bar">bar</a>
|
||||
```
|
||||
|
||||
### removeOptionalTags
|
||||
Remove certain tags that can be omitted, see [HTML Standard - 13.1.2.4 Optional tags](https://html.spec.whatwg.org/multipage/syntax.html#optional-tags).
|
||||
|
||||
#### Example
|
||||
|
||||
Source:
|
||||
|
||||
```html
|
||||
<html><head><title>Title</title></head><body><p>Hi</p></body></html>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<title>Title</title><p>Hi</p>
|
||||
```
|
||||
|
||||
#### Notice
|
||||
Due to [the limitation of PostHTML](https://github.com/posthtml/htmlnano/issues/99), htmlnano can't remove only the start tag or the end tag of an element. Currently, htmlnano only supports removing the following optional tags, as htmlnano can remove their start tag and end tag at the same time:
|
||||
|
||||
- `html`
|
||||
- `head`
|
||||
- `body`
|
||||
- `colgroup`
|
||||
- `tbody`
|
||||
|
||||
### normalizeAttributeValues
|
||||
|
||||
Normalize casing of attribute values.
|
||||
|
||||
The module won't impact the plain-text size of the output. However it will improve the compression ratio of gzip/brotli used in HTTP compression.
|
||||
|
||||
#### Example
|
||||
|
||||
Source:
|
||||
|
||||
```html
|
||||
<form method="GET"></form>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<form method="get"></form>
|
||||
```
|
||||
16
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-1.1.1/060-contribute.md
generated
vendored
Normal file
16
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-1.1.1/060-contribute.md
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
# Contribute
|
||||
|
||||
Since the minifier is modular, it's very easy to add new modules:
|
||||
|
||||
1. Create a ES6-file inside `lib/modules/` with a function that does some minification. For example you can check [`lib/modules/example.mjs`](https://github.com/posthtml/htmlnano/blob/master/lib/modules/example.mjs).
|
||||
|
||||
2. Add the module's name into one of those [presets](https://github.com/posthtml/htmlnano/tree/master/lib/presets). You can choose either `ampSafe`, `max`, or `safe`.
|
||||
|
||||
3. Create a JS-file inside `test/modules/` with some unit-tests.
|
||||
|
||||
4. Describe your module in the section "[Modules](https://github.com/posthtml/htmlnano/blob/master/README.md#modules)".
|
||||
|
||||
5. Send me a pull request.
|
||||
|
||||
Other types of contribution (bug fixes, documentation improves, etc) are also welcome!
|
||||
Would like to contribute, but don't have any ideas what to do? Check out [our issues](https://github.com/posthtml/htmlnano/labels/help%20wanted).
|
||||
22
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-2.0.0/010-introduction.md
generated
vendored
Normal file
22
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-2.0.0/010-introduction.md
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
slug: /
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
Modular HTML minifier, built on top of the [PostHTML](https://github.com/posthtml/posthtml).
|
||||
Inspired by [cssnano](http://cssnano.co/).
|
||||
|
||||
|
||||
## [Benchmark](https://github.com/maltsev/html-minifiers-benchmark/blob/master/README.md)
|
||||
[html-minifier-terser@5.1.1]: https://www.npmjs.com/package/html-minifier-terser
|
||||
[htmlnano@2.0.0]: https://www.npmjs.com/package/htmlnano
|
||||
|
||||
| Website | Source (KB) | [html-minifier-terser@5.1.1] | [htmlnano@2.0.0] |
|
||||
|---------|------------:|----------------:|-----------:|
|
||||
| [stackoverflow.blog](https://stackoverflow.blog/) | 95 | 87 | 82 |
|
||||
| [github.com](https://github.com/) | 210 | 183 | 171 |
|
||||
| [en.wikipedia.org](https://en.wikipedia.org/wiki/Main_Page) | 78 | 72 | 72 |
|
||||
| [npmjs.com](https://www.npmjs.com/features) | 41 | 38 | 36 |
|
||||
| **Avg. minify rate** | 0% | **9%** | **13%** |
|
||||
77
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-2.0.0/020-usage.md
generated
vendored
Normal file
77
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-2.0.0/020-usage.md
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
# Usage
|
||||
|
||||
## Gulp
|
||||
```bash
|
||||
npm install --save-dev gulp-htmlnano
|
||||
```
|
||||
|
||||
```js
|
||||
const gulp = require('gulp');
|
||||
const htmlnano = require('gulp-htmlnano');
|
||||
const options = {
|
||||
removeComments: false
|
||||
};
|
||||
|
||||
gulp.task('default', function() {
|
||||
return gulp
|
||||
.src('./index.html')
|
||||
.pipe(htmlnano(options))
|
||||
.pipe(gulp.dest('./build'));
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## Javascript
|
||||
```js
|
||||
const htmlnano = require('htmlnano');
|
||||
const options = {
|
||||
removeEmptyAttributes: false, // Disable the module "removeEmptyAttributes"
|
||||
collapseWhitespace: 'conservative' // Pass options to the module "collapseWhitespace"
|
||||
};
|
||||
// posthtml, posthtml-render, and posthtml-parse options
|
||||
const postHtmlOptions = {
|
||||
sync: true, // https://github.com/posthtml/posthtml#usage
|
||||
lowerCaseTags: true, // https://github.com/posthtml/posthtml-parser#options
|
||||
quoteAllAttributes: false, // https://github.com/posthtml/posthtml-render#options
|
||||
};
|
||||
|
||||
htmlnano
|
||||
// "preset" arg might be skipped (see "Presets" section below for more info)
|
||||
// "postHtmlOptions" arg might be skipped
|
||||
.process(html, options, preset, postHtmlOptions)
|
||||
.then(function (result) {
|
||||
// result.html is minified
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## PostHTML
|
||||
Just add `htmlnano` as a final plugin:
|
||||
```js
|
||||
const posthtml = require('posthtml');
|
||||
const options = {
|
||||
removeComments: false, // Disable the module "removeComments"
|
||||
collapseWhitespace: 'conservative' // Pass options to the module "collapseWhitespace"
|
||||
};
|
||||
const posthtmlPlugins = [
|
||||
/* other PostHTML plugins */
|
||||
|
||||
require('htmlnano')(options)
|
||||
];
|
||||
|
||||
const posthtmlOptions = {
|
||||
// See PostHTML docs
|
||||
};
|
||||
|
||||
posthtml(posthtmlPlugins)
|
||||
.process(html, posthtmlOptions)
|
||||
.then(function (result) {
|
||||
// result.html is minified
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
```
|
||||
21
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-2.0.0/030-config.md
generated
vendored
Normal file
21
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-2.0.0/030-config.md
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Config
|
||||
|
||||
There are two main ways to configure htmlnano:
|
||||
|
||||
## Passing options to `htmlnano` directly
|
||||
This is the way described above in the examples.
|
||||
|
||||
## Using configuration file
|
||||
Alternatively, you might create a configuration file (e.g., `htmlnanorc.json` or `htmlnanorc.js`) or save options to `package.json` with `htmlnano` key.
|
||||
`htmlnano` uses `cosmiconfig`, so refer to [its documentation](https://github.com/davidtheclark/cosmiconfig/blob/main/README.md) for a more detailed description.
|
||||
|
||||
If you want to specify a preset that way, use `preset` key:
|
||||
|
||||
```json
|
||||
{
|
||||
"preset": "max",
|
||||
}
|
||||
```
|
||||
|
||||
Configuration files have lower precedence than passing options to `htmlnano` directly.
|
||||
So if you use both ways, then the configuration file would be ignored.
|
||||
75
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-2.0.0/040-presets.md
generated
vendored
Normal file
75
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-2.0.0/040-presets.md
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
# Presets
|
||||
|
||||
A preset is just an object with modules config.
|
||||
|
||||
Currently the following presets are available:
|
||||
- [safe](https://github.com/posthtml/htmlnano/blob/master/lib/presets/safe.mjs) — a default preset for minifying a regular HTML in a safe way (without breaking anything)
|
||||
- [ampSafe](https://github.com/posthtml/htmlnano/blob/master/lib/presets/ampSafe.mjs) - same as `safe` preset but for [AMP pages](https://www.ampproject.org/)
|
||||
- [max](https://github.com/posthtml/htmlnano/blob/master/lib/presets/max.mjs) - maximal minification (might break some pages)
|
||||
|
||||
|
||||
You can use them the following way:
|
||||
```js
|
||||
const htmlnano = require('htmlnano');
|
||||
const ampSafePreset = require('htmlnano').presets.ampSafe;
|
||||
const options = {
|
||||
// Your options
|
||||
};
|
||||
|
||||
htmlnano
|
||||
.process(html, options, ampSafePreset)
|
||||
.then(function (result) {
|
||||
// result.html is minified
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
```
|
||||
|
||||
If you skip `preset` argument [`safe`](https://github.com/posthtml/htmlnano/blob/master/lib/presets/safe.mjs) preset would be used by default.
|
||||
|
||||
|
||||
If you'd like to define your very own config without any presets pass an empty object as a preset:
|
||||
```js
|
||||
const htmlnano = require('htmlnano');
|
||||
const options = {
|
||||
// Your options
|
||||
};
|
||||
|
||||
htmlnano
|
||||
.process(html, options, {})
|
||||
.then(function (result) {
|
||||
// result.html is minified
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
You might create also your own presets:
|
||||
```js
|
||||
const htmlnano = require('htmlnano');
|
||||
// Preset for minifying email templates
|
||||
const emailPreset = {
|
||||
mergeStyles: true,
|
||||
minifyCss: {
|
||||
safe: true
|
||||
},
|
||||
};
|
||||
|
||||
const options = {
|
||||
// Some specific options
|
||||
};
|
||||
|
||||
htmlnano
|
||||
.process(html, options, emailPreset)
|
||||
.then(function (result) {
|
||||
// result.html is minified
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
```
|
||||
|
||||
Feel free [to submit a PR](https://github.com/posthtml/htmlnano/issues/new) with your preset if it might be useful for other developers as well.
|
||||
838
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-2.0.0/050-modules.md
generated
vendored
Normal file
838
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-2.0.0/050-modules.md
generated
vendored
Normal file
@@ -0,0 +1,838 @@
|
||||
# Modules
|
||||
|
||||
By default the modules should only perform safe transforms, see the module documentation below for details.
|
||||
You can disable modules by passing `false` as option, and enable them by passing `true`.
|
||||
|
||||
|
||||
### collapseAttributeWhitespace
|
||||
Collapse redundant white spaces in list-like attributes (`class`, `rel`, `ping`).
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<a class=" content page " style=" display: block; " href=" https://example.com"></a>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<a class="content page" style="display: block;" href="https://example.com"></a>
|
||||
```
|
||||
|
||||
|
||||
|
||||
### collapseWhitespace
|
||||
Collapses redundant white spaces (including new lines). It doesn’t affect white spaces in the elements `<style>`, `<textarea>`, `<script>` and `<pre>`.
|
||||
|
||||
#### Options
|
||||
- `conservative` — collapses all redundant white spaces to 1 space (default)
|
||||
- `aggressive` — collapses all whitespaces that are redundant and safe to remove
|
||||
- `all` — collapses all redundant white spaces
|
||||
|
||||
#### Side effects
|
||||
|
||||
*all*
|
||||
`<i>hello</i> <i>world</i>` or `<i>hello</i><br><i>world</i>` after minification will be rendered as `helloworld`.
|
||||
To prevent that use either the default `conservative` option, or the `aggressive` option.
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<div>
|
||||
hello world!
|
||||
<a href="#">answer</a>
|
||||
<style>div { color: red; } </style>
|
||||
<main></main>
|
||||
</div>
|
||||
```
|
||||
|
||||
Minified (with `all`):
|
||||
```html
|
||||
<div>hello world!<a href="#">answer</a><style>div { color: red; } </style><main></main></div>
|
||||
```
|
||||
|
||||
Minified (with `aggressive`):
|
||||
```html
|
||||
<div> hello world! <a href="#">answer</a> <style>div { color: red; } </style><main></main></div>
|
||||
```
|
||||
|
||||
Minified (with `conservative`):
|
||||
```html
|
||||
<div> hello world! <a href="#">answer</a> <style>div { color: red; } </style> <main></main> </div>
|
||||
```
|
||||
|
||||
|
||||
### deduplicateAttributeValues
|
||||
Remove duplicate values from list-like attributes (`class`, `rel`, `ping`).
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<div class="sidebar left sidebar"></div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<div class="sidebar left"></div>
|
||||
```
|
||||
|
||||
|
||||
### removeComments
|
||||
#### Options
|
||||
- `safe` – removes all HTML comments except the conditional comments and [`<!--noindex--><!--/noindex-->`](https://yandex.com/support/webmaster/controlling-robot/html.xml) (default)
|
||||
- `all` — removes all HTML comments
|
||||
- A `RegExp` — only HTML comments matching the given regexp will be removed.
|
||||
- A `Function` that returns boolean — removes HTML comments that can make the given callback function returns truthy value.
|
||||
|
||||
#### Example
|
||||
|
||||
Source:
|
||||
|
||||
```js
|
||||
{
|
||||
removeComments: 'all'
|
||||
}
|
||||
```
|
||||
|
||||
```html
|
||||
<div><!-- test --></div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<div></div>
|
||||
```
|
||||
|
||||
Source:
|
||||
|
||||
```js
|
||||
{
|
||||
removeComments: /<!--(\/)?noindex-->/
|
||||
}
|
||||
```
|
||||
|
||||
```html
|
||||
<div><!--noindex-->this text will not be indexed<!--/noindex-->Lorem ipsum dolor sit amet<!--more-->Lorem ipsum dolor sit amet</div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<div>this text will not be indexedLorem ipsum dolor sit amet<!--more-->Lorem ipsum dolor sit amet</div>
|
||||
```
|
||||
|
||||
Source:
|
||||
|
||||
```js
|
||||
{
|
||||
removeComments: (comments) => {
|
||||
if (comments.includes('noindex')) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```html
|
||||
<div><!--noindex-->this text will not be indexed<!--/noindex-->Lorem ipsum dolor sit amet<!--more-->Lorem ipsum dolor sit amet</div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<div>this text will not be indexedLorem ipsum dolor sit amet<!--more-->Lorem ipsum dolor sit amet</div>
|
||||
```
|
||||
|
||||
|
||||
### removeEmptyAttributes
|
||||
Removes empty [safe-to-remove](https://github.com/posthtml/htmlnano/blob/master/lib/modules/removeEmptyAttributes.mjs) attributes.
|
||||
|
||||
#### Side effects
|
||||
This module could break your styles or JS if you use selectors with attributes:
|
||||
```CSS
|
||||
img[style=""] {
|
||||
margin: 10px;
|
||||
}
|
||||
```
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<img src="foo.jpg" alt="" style="">
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<img src="foo.jpg" alt="">
|
||||
```
|
||||
|
||||
### removeAttributeQuotes
|
||||
Remove quotes around attributes when possible, see [HTML Standard - 12.1.2.3 Attributes - Unquoted attribute value syntax](https://html.spec.whatwg.org/multipage/syntax.html#attributes-2).
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<div class="foo" title="hello world"></div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<div class=foo title="hello world"></div>
|
||||
```
|
||||
|
||||
#### Notice
|
||||
The feature is implemented by [posthtml-render's `quoteAllAttributes`](https://github.com/posthtml/posthtml-render#options), which is one of the PostHTML's option. So `removeAttributeQuotes` could be overriden by other PostHTML's plugins and PostHTML's configuration.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
posthtml([
|
||||
htmlnano({
|
||||
removeAttributeQuotes: true
|
||||
})
|
||||
]).process(html, {
|
||||
quoteAllAttributes: true
|
||||
})
|
||||
```
|
||||
|
||||
`removeAttributeQuotes` will not work because PostHTML's `quoteAllAttributes` takes the priority.
|
||||
|
||||
### removeUnusedCss
|
||||
|
||||
Removes unused CSS inside `<style>` tags with either [uncss](https://github.com/uncss/uncss)
|
||||
or [PurgeCSS](https://github.com/FullHuman/purgecss).
|
||||
|
||||
#### With uncss
|
||||
|
||||
You have to install `uncss` in order to use this feature:
|
||||
|
||||
```bash
|
||||
npm install --save-dev uncss
|
||||
# if you prefer yarn
|
||||
# yarn add --dev uncss
|
||||
# if you prefer pnpm
|
||||
# pnpm install --save-dev uncss
|
||||
```
|
||||
|
||||
You can also use a mainted fork [@novaatwarren/uncss](https://www.npmjs.com/package/@novaatwarren/uncss) instead.
|
||||
|
||||
|
||||
##### Options
|
||||
See [the documentation of uncss](https://github.com/uncss/uncss) for all supported options.
|
||||
|
||||
uncss options can be passed directly to the `removeUnusedCss` module:
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
removeUnusedCss: {
|
||||
ignore: ['.do-not-remove']
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
The following uncss options are ignored if passed to the module:
|
||||
|
||||
- `stylesheets`
|
||||
- `ignoreSheets`
|
||||
- `raw`
|
||||
|
||||
#### With PurgeCSS
|
||||
|
||||
Use PurgeCSS instead of uncss by adding `tool: 'purgeCSS'` to the options.
|
||||
|
||||
You have to install `purgecss` in order to use this feature:
|
||||
|
||||
```bash
|
||||
npm install --save-dev purgecss
|
||||
# if you prefer yarn
|
||||
# yarn add --dev purgecss
|
||||
# if you prefer pnpm
|
||||
# pnpm install --save-dev purgecss
|
||||
```
|
||||
|
||||
##### Options
|
||||
|
||||
See [the documentation of PurgeCSS](https://www.purgecss.com) for all supported options.
|
||||
|
||||
PurgeCSS options can be passed directly to the `removeUnusedCss` module:
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
removeUnusedCss: {
|
||||
tool: 'purgeCSS',
|
||||
safelist: ['.do-not-remove']
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
The following PurgeCSS options are ignored if passed to the module:
|
||||
|
||||
- `content`
|
||||
- `css`
|
||||
- `extractors`
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<div class="b">
|
||||
<style>
|
||||
.a {
|
||||
margin: 10px 10px 10px 10px;
|
||||
}
|
||||
.b {
|
||||
color: #ff0000;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
```
|
||||
|
||||
Optimized:
|
||||
```html
|
||||
<div class="b">
|
||||
<style>
|
||||
.b {
|
||||
color: #ff0000;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
### minifyCss
|
||||
Minifies CSS with [cssnano](http://cssnano.co/) inside `<style>` tags and `style` attributes.
|
||||
|
||||
You have to install `cssnano` and `postcss` in order to use this feature:
|
||||
|
||||
```bash
|
||||
npm install --save-dev cssnano postcss
|
||||
# if you prefer yarn
|
||||
# yarn add --dev cssnano postcss
|
||||
# if you prefer pnpm
|
||||
# pnpm install --save-dev cssnano postcss
|
||||
```
|
||||
|
||||
#### Options
|
||||
See [the documentation of cssnano](http://cssnano.co/docs/optimisations/) for all supported optimizations.
|
||||
By default CSS is minified with preset `default`, which shouldn't have any side-effects.
|
||||
|
||||
To use another preset or disabled some optimizations pass options to `minifyCss` module:
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyCss: {
|
||||
preset: ['default', {
|
||||
discardComments: {
|
||||
removeAll: true,
|
||||
},
|
||||
}]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<div>
|
||||
<style>
|
||||
h1 {
|
||||
margin: 10px 10px 10px 10px;
|
||||
color: #ff0000;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<div>
|
||||
<style>h1{margin:10px;color:red}</style>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
### minifyJs
|
||||
Minifies JS using [Terser](https://github.com/fabiosantoscode/terser) inside `<script>` tags.
|
||||
|
||||
You have to install `terser` in order to use this feature:
|
||||
|
||||
```bash
|
||||
npm install --save-dev terser
|
||||
# if you prefer yarn
|
||||
# yarn add --dev terser
|
||||
# if you prefer pnpm
|
||||
# pnpm install --save-dev terser
|
||||
```
|
||||
|
||||
#### Options
|
||||
See [the documentation of Terser](https://github.com/fabiosantoscode/terser#api-reference) for all supported options.
|
||||
Terser options can be passed directly to the `minifyJs` module:
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyJs: {
|
||||
output: { quote_style: 1 },
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<div>
|
||||
<script>
|
||||
/* comment */
|
||||
const foo = function () {
|
||||
|
||||
};
|
||||
</script>
|
||||
</div>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<div>
|
||||
<script>const foo=function(){};</script>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
### minifyJson
|
||||
Minifies JSON inside `<script type="application/json"></script>`.
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<script type="application/json">
|
||||
{
|
||||
"user": "me"
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<script type="application/json">{"user":"me"}</script>
|
||||
```
|
||||
|
||||
|
||||
### minifySvg
|
||||
Minifies SVG inside `<svg>` tags using [SVGO](https://github.com/svg/svgo/).
|
||||
|
||||
#### Options
|
||||
See [the documentation of SVGO](https://github.com/svg/svgo/blob/master/README.md) for all supported options.
|
||||
SVGO options can be passed directly to the `minifySvg` module:
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifySvg: {
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {
|
||||
builtinPluginName: {
|
||||
optionName: 'optionValue'
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<svg version="1.1" baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="100%" height="100%" fill="red" />
|
||||
|
||||
<circle cx="150" cy="100" r="80" fill="green" />
|
||||
|
||||
<text x="150" y="125" font-size="60" text-anchor="middle" fill="white">SVG</text>
|
||||
</svg>`
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<svg baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="red"/><circle cx="150" cy="100" r="80" fill="green"/><text x="150" y="125" font-size="60" text-anchor="middle" fill="#fff">SVG</text></svg>
|
||||
```
|
||||
|
||||
### minifyConditionalComments
|
||||
|
||||
Minify content inside conditional comments.
|
||||
|
||||
#### Example
|
||||
|
||||
Source:
|
||||
|
||||
```html
|
||||
<!--[if lte IE 7]>
|
||||
<style type="text/css">
|
||||
.title {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
<![endif]-->
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<!--[if lte IE 7]><style>.title{color:red}</style><![endif]-->
|
||||
```
|
||||
|
||||
### removeRedundantAttributes
|
||||
Removes redundant attributes from tags if they contain default values:
|
||||
- `method="get"` from `<form>`
|
||||
- `type="text"` from `<input>`
|
||||
- `type="submit"` from `<button>`
|
||||
- `language="javascript"` and `type="text/javascript"` from `<script>`
|
||||
- `charset` from `<script>` if it's an external script
|
||||
- `media="all"` from `<style>` and `<link>`
|
||||
- `type="text/css"` from `<link rel="stylesheet">`
|
||||
|
||||
#### Options
|
||||
This module is disabled by default, change option to true to enable this module.
|
||||
|
||||
#### Side effects
|
||||
This module could break your styles or JS if you use selectors with attributes:
|
||||
```CSS
|
||||
form[method="get"] {
|
||||
color: red;
|
||||
}
|
||||
```
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<form method="get">
|
||||
<input type="text">
|
||||
</form>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<form>
|
||||
<input>
|
||||
</form>
|
||||
```
|
||||
|
||||
|
||||
### collapseBooleanAttributes
|
||||
Collapses boolean attributes (like `disabled`) to the minimized form.
|
||||
|
||||
#### Options
|
||||
If your document uses [AMP](https://www.ampproject.org/), set the `amphtml` flag
|
||||
to collapse additonal, AMP-specific boolean attributes:
|
||||
```Json
|
||||
"collapseBooleanAttributes": {
|
||||
"amphtml": true
|
||||
}
|
||||
```
|
||||
|
||||
#### Side effects
|
||||
This module could break your styles or JS if you use selectors with attributes:
|
||||
```CSS
|
||||
button[disabled="disabled"] {
|
||||
color: red;
|
||||
}
|
||||
```
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<button disabled="disabled">click</button>
|
||||
<script defer=""></script>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<button disabled>click</button>
|
||||
<script defer></script>
|
||||
```
|
||||
|
||||
|
||||
### mergeStyles
|
||||
Merges multiple `<style>` with the same `media` and `type` into one tag.
|
||||
`<style scoped>...</style>` are skipped.
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<style>h1 { color: red }</style>
|
||||
<style media="print">div { color: blue }</style>
|
||||
|
||||
<style type="text/css" media="print">a {}</style>
|
||||
<style>div { font-size: 20px }</style>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<style>h1 { color: red } div { font-size: 20px }</style>
|
||||
<style media="print">div { color: blue } a {}</style>
|
||||
```
|
||||
|
||||
|
||||
### mergeScripts
|
||||
Merge multiple `<script>` with the same attributes (`id, class, type, async, defer`) into one (last) tag.
|
||||
|
||||
#### Side effects
|
||||
It could break your code if the tags with different attributes share the same variable scope.
|
||||
See the example below.
|
||||
|
||||
#### Example
|
||||
Source:
|
||||
```html
|
||||
<script>const foo = 'A:1';</script>
|
||||
<script class="test">foo = 'B:1';</script>
|
||||
<script type="text/javascript">foo = 'A:2';</script>
|
||||
<script defer>foo = 'C:1';</script>
|
||||
<script>foo = 'A:3';</script>
|
||||
<script defer="defer">foo = 'C:2';</script>
|
||||
<script class="test" type="text/javascript">foo = 'B:2';</script>
|
||||
```
|
||||
|
||||
Minified:
|
||||
```html
|
||||
<script>const foo = 'A:1'; foo = 'A:2'; foo = 'A:3';</script>
|
||||
<script defer="defer">foo = 'C:1'; foo = 'C:2';</script>
|
||||
<script class="test" type="text/javascript">foo = 'B:1'; foo = 'B:2';</script>
|
||||
```
|
||||
|
||||
|
||||
### custom
|
||||
It's also possible to pass custom modules in the minifier.
|
||||
As a function:
|
||||
```js
|
||||
const options = {
|
||||
custom: function (tree, options) {
|
||||
// Some minification
|
||||
return tree;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Or as a list of functions:
|
||||
```js
|
||||
const options = {
|
||||
custom: [
|
||||
function (tree, options) {
|
||||
// Some minification
|
||||
return tree;
|
||||
},
|
||||
|
||||
function (tree, options) {
|
||||
// Some other minification
|
||||
return tree;
|
||||
}
|
||||
]
|
||||
};
|
||||
```
|
||||
|
||||
`options` is an object with all options that were passed to the plugin.
|
||||
|
||||
### sortAttributesWithLists
|
||||
Sort values in list-like attributes (`class`, `rel`, `ping`).
|
||||
|
||||
The module won't impact the plain-text size of the output. However it will improve the compression ratio of gzip/brotli used in HTTP compression.
|
||||
|
||||
#### Options
|
||||
|
||||
- `alphabetical`: Default option. Sort attribute values in alphabetical order.
|
||||
- `frequency`: Sort attribute values by frequency.
|
||||
|
||||
#### Example
|
||||
|
||||
**alphabetical**
|
||||
|
||||
Source:
|
||||
```html
|
||||
<div class="foo baz bar">click</div>
|
||||
```
|
||||
|
||||
Processed:
|
||||
```html
|
||||
<div class="bar baz foo">click</div>
|
||||
```
|
||||
|
||||
**frequency**
|
||||
|
||||
Source:
|
||||
```html
|
||||
<div class="foo baz bar"></div><div class="bar foo"></div>
|
||||
```
|
||||
|
||||
Processed:
|
||||
```html
|
||||
<div class="foo bar baz"></div><div class="foo bar"></div>
|
||||
```
|
||||
|
||||
### sortAttributes
|
||||
Sort attributes inside elements.
|
||||
|
||||
The module won't impact the plain-text size of the output. However it will improve the compression ratio of gzip/brotli used in HTTP compression.
|
||||
|
||||
#### Options
|
||||
|
||||
- `alphabetical`: Default option. Sort attributes in alphabetical order.
|
||||
- `frequency`: Sort attributes by frequency.
|
||||
|
||||
#### Example
|
||||
|
||||
**alphabetical**
|
||||
|
||||
Source:
|
||||
```html
|
||||
<input type="text" class="form-control" name="testInput" autofocus="" autocomplete="off" id="testId">
|
||||
```
|
||||
|
||||
Processed:
|
||||
```html
|
||||
<input autocomplete="off" autofocus="" class="form-control" id="testId" name="testInput" type="text">
|
||||
```
|
||||
|
||||
**frequency**
|
||||
|
||||
Source:
|
||||
```html
|
||||
<input type="text" class="form-control" name="testInput" id="testId">
|
||||
<a id="testId" href="#" class="testClass"></a>
|
||||
<img width="20" src="../images/image.png" height="40" alt="image" class="cls" id="id2">
|
||||
```
|
||||
|
||||
Processed:
|
||||
```html
|
||||
<input class="form-control" id="testId" type="text" name="testInput">
|
||||
<a class="testClass" id="testId" href="#"></a>
|
||||
<img class="cls" id="id2" width="20" src="../images/image.png" height="40" alt="image">
|
||||
```
|
||||
|
||||
### minifyUrls
|
||||
Convert absolute URL to relative URL using [relateurl](https://www.npmjs.com/package/relateurl).
|
||||
|
||||
You have to install `relateurl`, `terser` and `srcset` in order to use this feature:
|
||||
|
||||
```bash
|
||||
npm install --save-dev relateurl terser srcset
|
||||
# if you prefer yarn
|
||||
# yarn add --dev relateurl terser srcset
|
||||
# if you prefer pnpm
|
||||
# pnpm install --save-dev relateurl terser srcset
|
||||
```
|
||||
|
||||
#### Options
|
||||
|
||||
The base URL to resolve against. Support `String` & `URL`.
|
||||
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyUrls: 'https://example.com' // Valid configuration
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyUrls: new URL('https://example.com') // Valid configuration
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyUrls: false // The module will be disabled
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyUrls: true // Invalid configuration, the module will be disabled
|
||||
});
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
**Basic Usage**
|
||||
|
||||
Configuration:
|
||||
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyUrls: 'https://example.com'
|
||||
});
|
||||
```
|
||||
|
||||
Source:
|
||||
|
||||
```html
|
||||
<a href="https://example.com/foo/bar/baz">bar</a>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<a href="foo/bar/baz">bar</a>
|
||||
```
|
||||
|
||||
**With sub-directory**
|
||||
|
||||
Configuration:
|
||||
|
||||
```js
|
||||
htmlnano.process(html, {
|
||||
minifyUrls: 'https://example.com/foo/baz/'
|
||||
});
|
||||
```
|
||||
|
||||
Source:
|
||||
|
||||
```html
|
||||
<a href="https://example.com/foo/bar">bar</a>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<a href="../bar">bar</a>
|
||||
```
|
||||
|
||||
### removeOptionalTags
|
||||
Remove certain tags that can be omitted, see [HTML Standard - 13.1.2.4 Optional tags](https://html.spec.whatwg.org/multipage/syntax.html#optional-tags).
|
||||
|
||||
#### Example
|
||||
|
||||
Source:
|
||||
|
||||
```html
|
||||
<html><head><title>Title</title></head><body><p>Hi</p></body></html>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<title>Title</title><p>Hi</p>
|
||||
```
|
||||
|
||||
#### Notice
|
||||
Due to [the limitation of PostHTML](https://github.com/posthtml/htmlnano/issues/99), htmlnano can't remove only the start tag or the end tag of an element. Currently, htmlnano only supports removing the following optional tags, as htmlnano can remove their start tag and end tag at the same time:
|
||||
|
||||
- `html`
|
||||
- `head`
|
||||
- `body`
|
||||
- `colgroup`
|
||||
- `tbody`
|
||||
|
||||
### normalizeAttributeValues
|
||||
|
||||
Normalize casing of attribute values.
|
||||
|
||||
The module won't impact the plain-text size of the output. However it will improve the compression ratio of gzip/brotli used in HTTP compression.
|
||||
|
||||
#### Example
|
||||
|
||||
Source:
|
||||
|
||||
```html
|
||||
<form method="GET"></form>
|
||||
```
|
||||
|
||||
Minified:
|
||||
|
||||
```html
|
||||
<form method="get"></form>
|
||||
```
|
||||
16
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-2.0.0/060-contribute.md
generated
vendored
Normal file
16
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_docs/version-2.0.0/060-contribute.md
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
# Contribute
|
||||
|
||||
Since the minifier is modular, it's very easy to add new modules:
|
||||
|
||||
1. Create a ES6-file inside `lib/modules/` with a function that does some minification. For example you can check [`lib/modules/example.mjs`](https://github.com/posthtml/htmlnano/blob/master/lib/modules/example.mjs).
|
||||
|
||||
2. Add the module's name into one of those [presets](https://github.com/posthtml/htmlnano/tree/master/lib/presets). You can choose either `ampSafe`, `max`, or `safe`.
|
||||
|
||||
3. Create a JS-file inside `test/modules/` with some unit-tests.
|
||||
|
||||
4. Describe your module in the section "[Modules](https://github.com/posthtml/htmlnano/blob/master/README.md#modules)".
|
||||
|
||||
5. Send me a pull request.
|
||||
|
||||
Other types of contribution (bug fixes, documentation improves, etc) are also welcome!
|
||||
Would like to contribute, but don't have any ideas what to do? Check out [our issues](https://github.com/posthtml/htmlnano/labels/help%20wanted).
|
||||
8
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_sidebars/version-1.1.1-sidebars.json
generated
vendored
Normal file
8
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_sidebars/version-1.1.1-sidebars.json
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"version-1.1.1/tutorialSidebar": [
|
||||
{
|
||||
"type": "autogenerated",
|
||||
"dirName": "."
|
||||
}
|
||||
]
|
||||
}
|
||||
8
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_sidebars/version-2.0.0-sidebars.json
generated
vendored
Normal file
8
webGl/my-threejs-test/node_modules/htmlnano/docs/versioned_sidebars/version-2.0.0-sidebars.json
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"version-2.0.0/tutorialSidebar": [
|
||||
{
|
||||
"type": "autogenerated",
|
||||
"dirName": "."
|
||||
}
|
||||
]
|
||||
}
|
||||
4
webGl/my-threejs-test/node_modules/htmlnano/docs/versions.json
generated
vendored
Normal file
4
webGl/my-threejs-test/node_modules/htmlnano/docs/versions.json
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
[
|
||||
"2.0.0",
|
||||
"1.1.1"
|
||||
]
|
||||
11
webGl/my-threejs-test/node_modules/htmlnano/index.cjs
generated
vendored
Normal file
11
webGl/my-threejs-test/node_modules/htmlnano/index.cjs
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
|
||||
const htmlnano = require("./lib/htmlnano.cjs").default;
|
||||
exports.default = htmlnano;
|
||||
|
||||
// for backward compatibility with require('htmlnano')
|
||||
module.exports = htmlnano;
|
||||
3
webGl/my-threejs-test/node_modules/htmlnano/index.d.cts
generated
vendored
Normal file
3
webGl/my-threejs-test/node_modules/htmlnano/index.d.cts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export type * from './index.d';
|
||||
import htmlnano from './index.d';
|
||||
export default htmlnano;
|
||||
3
webGl/my-threejs-test/node_modules/htmlnano/index.d.mts
generated
vendored
Normal file
3
webGl/my-threejs-test/node_modules/htmlnano/index.d.mts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export type * from './index.d';
|
||||
import htmlnano from './index.d';
|
||||
export default htmlnano;
|
||||
93
webGl/my-threejs-test/node_modules/htmlnano/index.d.ts
generated
vendored
Normal file
93
webGl/my-threejs-test/node_modules/htmlnano/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
import type PostHTML from "posthtml";
|
||||
import type { MinifyOptions } from "terser";
|
||||
import type { Options as CssNanoOptions } from "cssnano";
|
||||
import type { Config as SvgoOptimizeOptions } from "svgo";
|
||||
|
||||
export interface HtmlnanoOptions {
|
||||
skipConfigLoading?: boolean;
|
||||
collapseAttributeWhitespace?: boolean;
|
||||
collapseBooleanAttributes?: {
|
||||
amphtml?: boolean;
|
||||
};
|
||||
collapseWhitespace?: "conservative" | "all" | "aggressive";
|
||||
custom?: (tree: PostHTML.Node, options?: any) => PostHTML.Node;
|
||||
deduplicateAttributeValues?: boolean;
|
||||
minifyUrls?: URL | string | false;
|
||||
mergeStyles?: boolean;
|
||||
mergeScripts?: boolean;
|
||||
minifyCss?: CssNanoOptions | boolean;
|
||||
minifyConditionalComments?: boolean;
|
||||
minifyJs?: MinifyOptions | boolean;
|
||||
minifyJson?: boolean;
|
||||
minifySvg?: SvgoOptimizeOptions | boolean;
|
||||
normalizeAttributeValues?: boolean;
|
||||
removeAttributeQuotes?: boolean;
|
||||
removeComments?: boolean | "safe" | "all" | RegExp | (() => boolean);
|
||||
removeEmptyAttributes?: boolean;
|
||||
removeRedundantAttributes?: boolean;
|
||||
removeOptionalTags?: boolean;
|
||||
removeUnusedCss?: boolean;
|
||||
sortAttributes?: boolean | "alphabetical" | "frequency";
|
||||
sortAttributesWithLists?: boolean | "alphabetical" | "frequency";
|
||||
}
|
||||
|
||||
export interface HtmlnanoPreset extends Omit<HtmlnanoOptions, "skipConfigLoading"> {}
|
||||
|
||||
export interface Presets {
|
||||
safe: HtmlnanoPreset;
|
||||
ampSafe: HtmlnanoPreset;
|
||||
max: HtmlnanoPreset;
|
||||
}
|
||||
|
||||
type Preset = Presets[keyof Presets];
|
||||
|
||||
export function loadConfig(
|
||||
options?: HtmlnanoOptions,
|
||||
preset?: Preset,
|
||||
configPath?: string
|
||||
): [HtmlnanoOptions | {}, Preset];
|
||||
|
||||
declare function htmlnano<TMessage>(
|
||||
options?: HtmlnanoOptions,
|
||||
preset?: Preset
|
||||
): (tree: PostHTML.Node) => Promise<PostHTML.Result<TMessage>>;
|
||||
|
||||
interface PostHtmlOptions {
|
||||
directives?: Array<{
|
||||
name: string | RegExp;
|
||||
start: string;
|
||||
end: string;
|
||||
}>;
|
||||
sourceLocations?: boolean;
|
||||
recognizeNoValueAttribute?: boolean;
|
||||
xmlMode?: boolean;
|
||||
decodeEntities?: boolean;
|
||||
lowerCaseTags?: boolean;
|
||||
lowerCaseAttributeNames?: boolean;
|
||||
recognizeCDATA?: boolean;
|
||||
recognizeSelfClosing?: boolean;
|
||||
Tokenizer?: any;
|
||||
}
|
||||
|
||||
declare namespace htmlnano {
|
||||
export function process<TMessage>(
|
||||
html: string,
|
||||
options?: HtmlnanoOptions,
|
||||
preset?: Preset,
|
||||
postHtmlOptions?: PostHtmlOptions
|
||||
): Promise<PostHTML.Result<TMessage>>;
|
||||
|
||||
export function getRequiredOptionalDependencies(
|
||||
optionsRun?: HtmlnanoOptions,
|
||||
presetRun?: Preset
|
||||
): string[];
|
||||
|
||||
export function htmlMinimizerWebpackPluginMinify(
|
||||
input: { [file: string]: string },
|
||||
minimizerOptions?: HtmlnanoOptions
|
||||
): any;
|
||||
|
||||
export const presets: Presets;
|
||||
}
|
||||
|
||||
export default htmlnano;
|
||||
2
webGl/my-threejs-test/node_modules/htmlnano/index.mjs
generated
vendored
Normal file
2
webGl/my-threejs-test/node_modules/htmlnano/index.mjs
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import htmlnano from './lib/htmlnano.mjs';
|
||||
export default htmlnano;
|
||||
78
webGl/my-threejs-test/node_modules/htmlnano/lib/helpers.cjs
generated
vendored
Normal file
78
webGl/my-threejs-test/node_modules/htmlnano/lib/helpers.cjs
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.extractCssFromStyleNode = extractCssFromStyleNode;
|
||||
exports.isAmpBoilerplate = isAmpBoilerplate;
|
||||
exports.isComment = isComment;
|
||||
exports.isConditionalComment = isConditionalComment;
|
||||
exports.isEventHandler = isEventHandler;
|
||||
exports.isStyleNode = isStyleNode;
|
||||
exports.optionalImport = optionalImport;
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
function __transformExtension(filepath, extMapping) {
|
||||
if (!filepath.startsWith('./') && !filepath.startsWith('../')) {
|
||||
// Package import
|
||||
return filepath;
|
||||
}
|
||||
const idx = filepath.lastIndexOf('.');
|
||||
if (idx === -1 || filepath.includes('/', idx)) {
|
||||
// No extension
|
||||
const newExt = extMapping[''];
|
||||
if (newExt) {
|
||||
return filepath + newExt;
|
||||
}
|
||||
return filepath;
|
||||
}
|
||||
for (let [origExt, newExt] of Object.entries(extMapping).sort((a, b) => b[0].length - a[0].length)) {
|
||||
if (filepath.endsWith(origExt)) {
|
||||
return filepath.slice(0, -origExt.length) + newExt;
|
||||
}
|
||||
}
|
||||
return filepath;
|
||||
}
|
||||
const ampBoilerplateAttributes = ['amp-boilerplate', 'amp4ads-boilerplate', 'amp4email-boilerplate'];
|
||||
function isAmpBoilerplate(node) {
|
||||
if (!node.attrs) {
|
||||
return false;
|
||||
}
|
||||
for (const attr of ampBoilerplateAttributes) {
|
||||
if (attr in node.attrs) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function isComment(content) {
|
||||
if (typeof content === 'string') {
|
||||
return content.trim().startsWith('<!--');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function isConditionalComment(content) {
|
||||
return (content || '').trim().startsWith('<!--[if');
|
||||
}
|
||||
function isStyleNode(node) {
|
||||
return node.tag === 'style' && !isAmpBoilerplate(node) && 'content' in node && node.content.length > 0;
|
||||
}
|
||||
function extractCssFromStyleNode(node) {
|
||||
return Array.isArray(node.content) ? node.content.join(' ') : node.content;
|
||||
}
|
||||
function isEventHandler(attributeName) {
|
||||
return attributeName && attributeName.slice && attributeName.slice(0, 2).toLowerCase() === 'on' && attributeName.length >= 5;
|
||||
}
|
||||
async function optionalImport(moduleName) {
|
||||
try {
|
||||
const module = await (specifier => new Promise(r => r(`${specifier}`)).then(s => _interopRequireWildcard(require(s))))(__transformExtension(moduleName, {
|
||||
".mjs": ".cjs"
|
||||
}));
|
||||
return module.default || module;
|
||||
} catch (e) {
|
||||
if (e.code === 'MODULE_NOT_FOUND' || e.code === 'ERR_MODULE_NOT_FOUND') {
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
52
webGl/my-threejs-test/node_modules/htmlnano/lib/helpers.mjs
generated
vendored
Normal file
52
webGl/my-threejs-test/node_modules/htmlnano/lib/helpers.mjs
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
const ampBoilerplateAttributes = [
|
||||
'amp-boilerplate',
|
||||
'amp4ads-boilerplate',
|
||||
'amp4email-boilerplate'
|
||||
];
|
||||
|
||||
export function isAmpBoilerplate(node) {
|
||||
if (!node.attrs) {
|
||||
return false;
|
||||
}
|
||||
for (const attr of ampBoilerplateAttributes) {
|
||||
if (attr in node.attrs) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isComment(content) {
|
||||
if (typeof content === 'string') {
|
||||
return content.trim().startsWith('<!--');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isConditionalComment(content) {
|
||||
return (content || '').trim().startsWith('<!--[if');
|
||||
}
|
||||
|
||||
export function isStyleNode(node) {
|
||||
return node.tag === 'style' && !isAmpBoilerplate(node) && 'content' in node && node.content.length > 0;
|
||||
}
|
||||
|
||||
export function extractCssFromStyleNode(node) {
|
||||
return Array.isArray(node.content) ? node.content.join(' ') : node.content;
|
||||
}
|
||||
|
||||
export function isEventHandler(attributeName) {
|
||||
return attributeName && attributeName.slice && attributeName.slice(0, 2).toLowerCase() === 'on' && attributeName.length >= 5;
|
||||
}
|
||||
|
||||
export async function optionalImport(moduleName) {
|
||||
try {
|
||||
const module = await import(moduleName);
|
||||
return module.default || module;
|
||||
} catch (e) {
|
||||
if (e.code === 'MODULE_NOT_FOUND' || e.code === 'ERR_MODULE_NOT_FOUND') {
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
200
webGl/my-threejs-test/node_modules/htmlnano/lib/htmlnano.cjs
generated
vendored
Normal file
200
webGl/my-threejs-test/node_modules/htmlnano/lib/htmlnano.cjs
generated
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
exports.loadConfig = loadConfig;
|
||||
var _posthtml = _interopRequireDefault(require("posthtml"));
|
||||
var _cosmiconfig = require("cosmiconfig");
|
||||
var _safe = _interopRequireDefault(require("./presets/safe.cjs"));
|
||||
var _ampSafe = _interopRequireDefault(require("./presets/ampSafe.cjs"));
|
||||
var _max = _interopRequireDefault(require("./presets/max.cjs"));
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
function __transformExtension(filepath, extMapping) {
|
||||
if (!filepath.startsWith('./') && !filepath.startsWith('../')) {
|
||||
// Package import
|
||||
return filepath;
|
||||
}
|
||||
const idx = filepath.lastIndexOf('.');
|
||||
if (idx === -1 || filepath.includes('/', idx)) {
|
||||
// No extension
|
||||
const newExt = extMapping[''];
|
||||
if (newExt) {
|
||||
return filepath + newExt;
|
||||
}
|
||||
return filepath;
|
||||
}
|
||||
for (let [origExt, newExt] of Object.entries(extMapping).sort((a, b) => b[0].length - a[0].length)) {
|
||||
if (filepath.endsWith(origExt)) {
|
||||
return filepath.slice(0, -origExt.length) + newExt;
|
||||
}
|
||||
}
|
||||
return filepath;
|
||||
}
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
const presets = {
|
||||
safe: _safe.default,
|
||||
ampSafe: _ampSafe.default,
|
||||
max: _max.default
|
||||
};
|
||||
function loadConfig(options, preset, configPath) {
|
||||
let {
|
||||
skipConfigLoading = false,
|
||||
...rest
|
||||
} = options || {};
|
||||
if (!skipConfigLoading) {
|
||||
const explorer = (0, _cosmiconfig.cosmiconfigSync)('htmlnano');
|
||||
const rc = configPath ? explorer.load(configPath) : explorer.search();
|
||||
if (rc) {
|
||||
const {
|
||||
preset: presetName
|
||||
} = rc.config;
|
||||
if (presetName) {
|
||||
if (!preset && presets[presetName]) {
|
||||
preset = presets[presetName];
|
||||
}
|
||||
delete rc.config.preset;
|
||||
}
|
||||
if (!options) {
|
||||
rest = rc.config;
|
||||
}
|
||||
}
|
||||
}
|
||||
return [rest || {}, preset || _safe.default];
|
||||
}
|
||||
const optionalDependencies = {
|
||||
minifyCss: ['cssnano', 'postcss'],
|
||||
minifyJs: ['terser'],
|
||||
minifyUrl: ['relateurl', 'srcset', 'terser'],
|
||||
minifySvg: ['svgo']
|
||||
};
|
||||
const modules = {
|
||||
collapseAttributeWhitespace: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/collapseAttributeWhitespace.cjs"))),
|
||||
collapseBooleanAttributes: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/collapseBooleanAttributes.cjs"))),
|
||||
collapseWhitespace: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/collapseWhitespace.cjs"))),
|
||||
custom: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/custom.cjs"))),
|
||||
deduplicateAttributeValues: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/deduplicateAttributeValues.cjs"))),
|
||||
example: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/example.cjs"))),
|
||||
mergeScripts: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/mergeScripts.cjs"))),
|
||||
mergeStyles: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/mergeStyles.cjs"))),
|
||||
minifyConditionalComments: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/minifyConditionalComments.cjs"))),
|
||||
minifyCss: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/minifyCss.cjs"))),
|
||||
minifyJs: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/minifyJs.cjs"))),
|
||||
minifyJson: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/minifyJson.cjs"))),
|
||||
minifySvg: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/minifySvg.cjs"))),
|
||||
minifyUrls: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/minifyUrls.cjs"))),
|
||||
normalizeAttributeValues: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/normalizeAttributeValues.cjs"))),
|
||||
removeAttributeQuotes: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/removeAttributeQuotes.cjs"))),
|
||||
removeComments: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/removeComments.cjs"))),
|
||||
removeEmptyAttributes: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/removeEmptyAttributes.cjs"))),
|
||||
removeOptionalTags: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/removeOptionalTags.cjs"))),
|
||||
removeRedundantAttributes: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/removeRedundantAttributes.cjs"))),
|
||||
removeUnusedCss: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/removeUnusedCss.cjs"))),
|
||||
sortAttributes: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/sortAttributes.cjs"))),
|
||||
sortAttributesWithLists: () => Promise.resolve().then(() => _interopRequireWildcard(require("./modules/sortAttributesWithLists.cjs")))
|
||||
};
|
||||
function htmlnano(optionsRun, presetRun) {
|
||||
let [options, preset] = loadConfig(optionsRun, presetRun);
|
||||
return async function minifier(tree) {
|
||||
const nodeHandlers = [];
|
||||
const attrsHandlers = [];
|
||||
const contentsHandlers = [];
|
||||
options = {
|
||||
...preset,
|
||||
...options
|
||||
};
|
||||
let promise = Promise.resolve(tree);
|
||||
for (const [moduleName, moduleOptions] of Object.entries(options)) {
|
||||
if (!moduleOptions) {
|
||||
// The module is disabled
|
||||
continue;
|
||||
}
|
||||
if (_safe.default[moduleName] === undefined) {
|
||||
throw new Error('Module "' + moduleName + '" is not defined');
|
||||
}
|
||||
(optionalDependencies[moduleName] || []).forEach(async dependency => {
|
||||
try {
|
||||
await (specifier => new Promise(r => r(`${specifier}`)).then(s => _interopRequireWildcard(require(s))))(__transformExtension(dependency, {
|
||||
".mjs": ".cjs"
|
||||
}));
|
||||
} catch (e) {
|
||||
if (e.code === 'MODULE_NOT_FOUND' || e.code === 'ERR_MODULE_NOT_FOUND') {
|
||||
console.warn(`You have to install "${dependency}" in order to use htmlnano's "${moduleName}" module`);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
});
|
||||
const module = moduleName in modules ? await modules[moduleName]() : await (specifier => new Promise(r => r(`${specifier}`)).then(s => _interopRequireWildcard(require(s))))(__transformExtension(`./modules/${moduleName}.mjs`, {
|
||||
".mjs": ".cjs"
|
||||
}));
|
||||
if (typeof module.onAttrs === 'function') {
|
||||
attrsHandlers.push(module.onAttrs(options, moduleOptions));
|
||||
}
|
||||
if (typeof module.onContent === 'function') {
|
||||
contentsHandlers.push(module.onContent(options, moduleOptions));
|
||||
}
|
||||
if (typeof module.onNode === 'function') {
|
||||
nodeHandlers.push(module.onNode(options, moduleOptions));
|
||||
}
|
||||
if (typeof module.default === 'function') {
|
||||
promise = promise.then(async tree => await module.default(tree, options, moduleOptions));
|
||||
}
|
||||
}
|
||||
if (attrsHandlers.length + contentsHandlers.length + nodeHandlers.length === 0) {
|
||||
return promise;
|
||||
}
|
||||
return promise.then(tree => {
|
||||
tree.walk(node => {
|
||||
if (node) {
|
||||
if (node.attrs && typeof node.attrs === 'object') {
|
||||
// Convert all attrs' key to lower case
|
||||
let newAttrsObj = {};
|
||||
Object.entries(node.attrs).forEach(([attrName, attrValue]) => {
|
||||
newAttrsObj[attrName.toLowerCase()] = attrValue;
|
||||
});
|
||||
for (const handler of attrsHandlers) {
|
||||
newAttrsObj = handler(newAttrsObj, node);
|
||||
}
|
||||
node.attrs = newAttrsObj;
|
||||
}
|
||||
if (node.content) {
|
||||
node.content = typeof node.content === 'string' ? [node.content] : node.content;
|
||||
if (Array.isArray(node.content) && node.content.length > 0) {
|
||||
for (const handler of contentsHandlers) {
|
||||
const result = handler(node.content, node);
|
||||
node.content = typeof result === 'string' ? [result] : result;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const handler of nodeHandlers) {
|
||||
node = handler(node);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
});
|
||||
return tree;
|
||||
});
|
||||
};
|
||||
}
|
||||
htmlnano.getRequiredOptionalDependencies = function (optionsRun, presetRun) {
|
||||
const [options] = loadConfig(optionsRun, presetRun);
|
||||
return [...new Set(Object.keys(options).filter(moduleName => options[moduleName]).map(moduleName => optionalDependencies[moduleName]).flat())];
|
||||
};
|
||||
htmlnano.process = function (html, options, preset, postHtmlOptions) {
|
||||
return (0, _posthtml.default)([htmlnano(options, preset)]).process(html, postHtmlOptions);
|
||||
};
|
||||
|
||||
// https://github.com/webpack-contrib/html-minimizer-webpack-plugin/blob/faca00f2219514bc671c5942685721f0b5dbaa70/src/utils.js#L74
|
||||
htmlnano.htmlMinimizerWebpackPluginMinify = function htmlNano(input, minimizerOptions = {}) {
|
||||
const [[, code]] = Object.entries(input);
|
||||
return htmlnano.process(code, minimizerOptions, presets.safe).then(result => {
|
||||
return {
|
||||
code: result.html
|
||||
};
|
||||
});
|
||||
};
|
||||
htmlnano.presets = presets;
|
||||
var _default = exports.default = htmlnano;
|
||||
196
webGl/my-threejs-test/node_modules/htmlnano/lib/htmlnano.mjs
generated
vendored
Normal file
196
webGl/my-threejs-test/node_modules/htmlnano/lib/htmlnano.mjs
generated
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
import posthtml from 'posthtml';
|
||||
import { cosmiconfigSync } from 'cosmiconfig';
|
||||
import safePreset from './presets/safe.mjs';
|
||||
import ampSafePreset from './presets/ampSafe.mjs';
|
||||
import maxPreset from './presets/max.mjs';
|
||||
|
||||
const presets = {
|
||||
safe: safePreset,
|
||||
ampSafe: ampSafePreset,
|
||||
max: maxPreset,
|
||||
};
|
||||
|
||||
export function loadConfig(options, preset, configPath) {
|
||||
let { skipConfigLoading = false, ...rest } = options || {};
|
||||
|
||||
if (!skipConfigLoading) {
|
||||
const explorer = cosmiconfigSync('htmlnano');
|
||||
const rc = configPath ? explorer.load(configPath) : explorer.search();
|
||||
if (rc) {
|
||||
const { preset: presetName } = rc.config;
|
||||
if (presetName) {
|
||||
if (!preset && presets[presetName]) {
|
||||
preset = presets[presetName];
|
||||
}
|
||||
|
||||
delete rc.config.preset;
|
||||
}
|
||||
|
||||
if (!options) {
|
||||
rest = rc.config;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
rest || {},
|
||||
preset || safePreset,
|
||||
];
|
||||
}
|
||||
|
||||
const optionalDependencies = {
|
||||
minifyCss: ['cssnano', 'postcss'],
|
||||
minifyJs: ['terser'],
|
||||
minifyUrl: ['relateurl', 'srcset', 'terser'],
|
||||
minifySvg: ['svgo'],
|
||||
};
|
||||
|
||||
|
||||
const modules = {
|
||||
collapseAttributeWhitespace: () => import('./modules/collapseAttributeWhitespace.mjs'),
|
||||
collapseBooleanAttributes: () => import('./modules/collapseBooleanAttributes.mjs'),
|
||||
collapseWhitespace: () => import('./modules/collapseWhitespace.mjs'),
|
||||
custom: () => import('./modules/custom.mjs'),
|
||||
deduplicateAttributeValues: () => import('./modules/deduplicateAttributeValues.mjs'),
|
||||
example: () => import('./modules/example.mjs'),
|
||||
mergeScripts: () => import('./modules/mergeScripts.mjs'),
|
||||
mergeStyles: () => import('./modules/mergeStyles.mjs'),
|
||||
minifyConditionalComments: () => import('./modules/minifyConditionalComments.mjs'),
|
||||
minifyCss: () => import('./modules/minifyCss.mjs'),
|
||||
minifyJs: () => import('./modules/minifyJs.mjs'),
|
||||
minifyJson: () => import('./modules/minifyJson.mjs'),
|
||||
minifySvg: () => import('./modules/minifySvg.mjs'),
|
||||
minifyUrls: () => import('./modules/minifyUrls.mjs'),
|
||||
normalizeAttributeValues: () => import('./modules/normalizeAttributeValues.mjs'),
|
||||
removeAttributeQuotes: () => import('./modules/removeAttributeQuotes.mjs'),
|
||||
removeComments: () => import('./modules/removeComments.mjs'),
|
||||
removeEmptyAttributes: () => import('./modules/removeEmptyAttributes.mjs'),
|
||||
removeOptionalTags: () => import('./modules/removeOptionalTags.mjs'),
|
||||
removeRedundantAttributes: () => import('./modules/removeRedundantAttributes.mjs'),
|
||||
removeUnusedCss: () => import('./modules/removeUnusedCss.mjs'),
|
||||
sortAttributes: () => import('./modules/sortAttributes.mjs'),
|
||||
sortAttributesWithLists: () => import('./modules/sortAttributesWithLists.mjs'),
|
||||
};
|
||||
|
||||
function htmlnano(optionsRun, presetRun) {
|
||||
let [options, preset] = loadConfig(optionsRun, presetRun);
|
||||
|
||||
return async function minifier(tree) {
|
||||
const nodeHandlers = [];
|
||||
const attrsHandlers = [];
|
||||
const contentsHandlers = [];
|
||||
|
||||
options = { ...preset, ...options };
|
||||
let promise = Promise.resolve(tree);
|
||||
|
||||
for (const [moduleName, moduleOptions] of Object.entries(options)) {
|
||||
if (!moduleOptions) {
|
||||
// The module is disabled
|
||||
continue;
|
||||
}
|
||||
|
||||
if (safePreset[moduleName] === undefined) {
|
||||
throw new Error('Module "' + moduleName + '" is not defined');
|
||||
}
|
||||
|
||||
(optionalDependencies[moduleName] || []).forEach(async dependency => {
|
||||
try {
|
||||
await import(dependency);
|
||||
} catch (e) {
|
||||
if (e.code === 'MODULE_NOT_FOUND' || e.code === 'ERR_MODULE_NOT_FOUND') {
|
||||
console.warn(`You have to install "${dependency}" in order to use htmlnano's "${moduleName}" module`);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const module = moduleName in modules ?
|
||||
await (modules[moduleName]()) :
|
||||
await import(`./modules/${moduleName}.mjs`);
|
||||
|
||||
if (typeof module.onAttrs === 'function') {
|
||||
attrsHandlers.push(module.onAttrs(options, moduleOptions));
|
||||
}
|
||||
if (typeof module.onContent === 'function') {
|
||||
contentsHandlers.push(module.onContent(options, moduleOptions));
|
||||
}
|
||||
if (typeof module.onNode === 'function') {
|
||||
nodeHandlers.push(module.onNode(options, moduleOptions));
|
||||
}
|
||||
if (typeof module.default === 'function') {
|
||||
promise = promise.then(async tree => await module.default(tree, options, moduleOptions));
|
||||
}
|
||||
}
|
||||
|
||||
if (attrsHandlers.length + contentsHandlers.length + nodeHandlers.length === 0) {
|
||||
return promise;
|
||||
}
|
||||
|
||||
return promise.then(tree => {
|
||||
tree.walk(node => {
|
||||
if (node) {
|
||||
if (node.attrs && typeof node.attrs === 'object') {
|
||||
// Convert all attrs' key to lower case
|
||||
let newAttrsObj = {};
|
||||
Object.entries(node.attrs).forEach(([attrName, attrValue]) => {
|
||||
newAttrsObj[attrName.toLowerCase()] = attrValue;
|
||||
});
|
||||
|
||||
for (const handler of attrsHandlers) {
|
||||
newAttrsObj = handler(newAttrsObj, node);
|
||||
}
|
||||
|
||||
node.attrs = newAttrsObj;
|
||||
}
|
||||
|
||||
if (node.content) {
|
||||
node.content = typeof node.content === 'string' ? [node.content] : node.content;
|
||||
|
||||
if (Array.isArray(node.content) && node.content.length > 0) {
|
||||
for (const handler of contentsHandlers) {
|
||||
const result = handler(node.content, node);
|
||||
node.content = typeof result === 'string' ? [result] : result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const handler of nodeHandlers) {
|
||||
node = handler(node);
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
});
|
||||
|
||||
return tree;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
htmlnano.getRequiredOptionalDependencies = function (optionsRun, presetRun) {
|
||||
const [options] = loadConfig(optionsRun, presetRun);
|
||||
|
||||
return [...new Set(Object.keys(options).filter(moduleName => options[moduleName]).map(moduleName => optionalDependencies[moduleName]).flat())];
|
||||
};
|
||||
|
||||
|
||||
htmlnano.process = function (html, options, preset, postHtmlOptions) {
|
||||
return posthtml([htmlnano(options, preset)])
|
||||
.process(html, postHtmlOptions);
|
||||
};
|
||||
|
||||
// https://github.com/webpack-contrib/html-minimizer-webpack-plugin/blob/faca00f2219514bc671c5942685721f0b5dbaa70/src/utils.js#L74
|
||||
htmlnano.htmlMinimizerWebpackPluginMinify = function htmlNano(input, minimizerOptions = {}) {
|
||||
const [[, code]] = Object.entries(input);
|
||||
return htmlnano.process(code, minimizerOptions, presets.safe)
|
||||
.then(result => {
|
||||
return {
|
||||
code: result.html
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
htmlnano.presets = presets;
|
||||
|
||||
export default htmlnano;
|
||||
86
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/collapseAttributeWhitespace.cjs
generated
vendored
Normal file
86
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/collapseAttributeWhitespace.cjs
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.attributesWithLists = void 0;
|
||||
exports.onAttrs = onAttrs;
|
||||
var _helpers = require("../helpers.cjs");
|
||||
const attributesWithLists = exports.attributesWithLists = new Set(['class', 'dropzone', 'rel',
|
||||
// a, area, link
|
||||
'ping',
|
||||
// a, area
|
||||
'sandbox',
|
||||
// iframe
|
||||
/**
|
||||
* https://github.com/posthtml/htmlnano/issues/180
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#attr-sizes
|
||||
*
|
||||
* "sizes" of <img> should not be modified, while "sizes" of <link> will only have one entry in most cases.
|
||||
*/
|
||||
// 'sizes', // link
|
||||
'headers' // td, th
|
||||
]);
|
||||
|
||||
/** @type Record<string, string[] | null> */
|
||||
const attributesWithSingleValue = {
|
||||
accept: ['input'],
|
||||
action: ['form'],
|
||||
accesskey: null,
|
||||
'accept-charset': ['form'],
|
||||
cite: ['blockquote', 'del', 'ins', 'q'],
|
||||
cols: ['textarea'],
|
||||
colspan: ['td', 'th'],
|
||||
data: ['object'],
|
||||
dropzone: null,
|
||||
formaction: ['button', 'input'],
|
||||
height: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video'],
|
||||
high: ['meter'],
|
||||
href: ['a', 'area', 'base', 'link'],
|
||||
itemid: null,
|
||||
low: ['meter'],
|
||||
manifest: ['html'],
|
||||
max: ['meter', 'progress'],
|
||||
maxlength: ['input', 'textarea'],
|
||||
media: ['source'],
|
||||
min: ['meter'],
|
||||
minlength: ['input', 'textarea'],
|
||||
optimum: ['meter'],
|
||||
ping: ['a', 'area'],
|
||||
poster: ['video'],
|
||||
profile: ['head'],
|
||||
rows: ['textarea'],
|
||||
rowspan: ['td', 'th'],
|
||||
size: ['input', 'select'],
|
||||
span: ['col', 'colgroup'],
|
||||
src: ['audio', 'embed', 'iframe', 'img', 'input', 'script', 'source', 'track', 'video'],
|
||||
start: ['ol'],
|
||||
step: ['input'],
|
||||
style: null,
|
||||
tabindex: null,
|
||||
usemap: ['img', 'object'],
|
||||
value: ['li', 'meter', 'progress'],
|
||||
width: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video']
|
||||
};
|
||||
|
||||
/** Collapse whitespaces inside list-like attributes (e.g. class, rel) */
|
||||
function onAttrs() {
|
||||
return (attrs, node) => {
|
||||
const newAttrs = attrs;
|
||||
Object.entries(attrs).forEach(([attrName, attrValue]) => {
|
||||
if (typeof attrValue !== 'string') return;
|
||||
if (attributesWithLists.has(attrName)) {
|
||||
const newAttrValue = attrValue.replace(/\s+/g, ' ').trim();
|
||||
newAttrs[attrName] = newAttrValue;
|
||||
return;
|
||||
}
|
||||
if ((0, _helpers.isEventHandler)(attrName) || Object.prototype.hasOwnProperty.call(attributesWithSingleValue, attrName) && (attributesWithSingleValue[attrName] === null || attributesWithSingleValue[attrName].includes(node.tag))) {
|
||||
newAttrs[attrName] = minifySingleAttributeValue(attrValue);
|
||||
}
|
||||
});
|
||||
return newAttrs;
|
||||
};
|
||||
}
|
||||
function minifySingleAttributeValue(value) {
|
||||
return typeof value === 'string' ? value.trim() : value;
|
||||
}
|
||||
104
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/collapseAttributeWhitespace.mjs
generated
vendored
Normal file
104
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/collapseAttributeWhitespace.mjs
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
import { isEventHandler } from '../helpers.mjs';
|
||||
|
||||
export const attributesWithLists = new Set([
|
||||
'class',
|
||||
'dropzone',
|
||||
'rel', // a, area, link
|
||||
'ping', // a, area
|
||||
'sandbox', // iframe
|
||||
/**
|
||||
* https://github.com/posthtml/htmlnano/issues/180
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#attr-sizes
|
||||
*
|
||||
* "sizes" of <img> should not be modified, while "sizes" of <link> will only have one entry in most cases.
|
||||
*/
|
||||
// 'sizes', // link
|
||||
'headers' // td, th
|
||||
]);
|
||||
|
||||
/** @type Record<string, string[] | null> */
|
||||
const attributesWithSingleValue = {
|
||||
accept: ['input'],
|
||||
action: ['form'],
|
||||
accesskey: null,
|
||||
'accept-charset': ['form'],
|
||||
cite: ['blockquote', 'del', 'ins', 'q'],
|
||||
cols: ['textarea'],
|
||||
colspan: ['td', 'th'],
|
||||
data: ['object'],
|
||||
dropzone: null,
|
||||
formaction: ['button', 'input'],
|
||||
height: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video'],
|
||||
high: ['meter'],
|
||||
href: ['a', 'area', 'base', 'link'],
|
||||
itemid: null,
|
||||
low: ['meter'],
|
||||
manifest: ['html'],
|
||||
max: ['meter', 'progress'],
|
||||
maxlength: ['input', 'textarea'],
|
||||
media: ['source'],
|
||||
min: ['meter'],
|
||||
minlength: ['input', 'textarea'],
|
||||
optimum: ['meter'],
|
||||
ping: ['a', 'area'],
|
||||
poster: ['video'],
|
||||
profile: ['head'],
|
||||
rows: ['textarea'],
|
||||
rowspan: ['td', 'th'],
|
||||
size: ['input', 'select'],
|
||||
span: ['col', 'colgroup'],
|
||||
src: [
|
||||
'audio',
|
||||
'embed',
|
||||
'iframe',
|
||||
'img',
|
||||
'input',
|
||||
'script',
|
||||
'source',
|
||||
'track',
|
||||
'video'
|
||||
],
|
||||
start: ['ol'],
|
||||
step: ['input'],
|
||||
style: null,
|
||||
tabindex: null,
|
||||
usemap: ['img', 'object'],
|
||||
value: ['li', 'meter', 'progress'],
|
||||
width: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video']
|
||||
};
|
||||
|
||||
/** Collapse whitespaces inside list-like attributes (e.g. class, rel) */
|
||||
export function onAttrs() {
|
||||
return (attrs, node) => {
|
||||
const newAttrs = attrs;
|
||||
|
||||
Object.entries(attrs).forEach(([attrName, attrValue]) => {
|
||||
if (typeof attrValue !== 'string') return;
|
||||
|
||||
if (attributesWithLists.has(attrName)) {
|
||||
const newAttrValue = attrValue.replace(/\s+/g, ' ').trim();
|
||||
newAttrs[attrName] = newAttrValue;
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
isEventHandler(attrName)
|
||||
|| (
|
||||
Object.prototype.hasOwnProperty.call(attributesWithSingleValue, attrName)
|
||||
&& (
|
||||
attributesWithSingleValue[attrName] === null
|
||||
|| attributesWithSingleValue[attrName].includes(node.tag)
|
||||
)
|
||||
)
|
||||
) {
|
||||
newAttrs[attrName] = minifySingleAttributeValue(attrValue);
|
||||
}
|
||||
});
|
||||
|
||||
return newAttrs;
|
||||
};
|
||||
}
|
||||
|
||||
function minifySingleAttributeValue(value) {
|
||||
return typeof value === 'string' ? value.trim() : value;
|
||||
}
|
||||
62
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/collapseBooleanAttributes.cjs
generated
vendored
Normal file
62
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/collapseBooleanAttributes.cjs
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.onAttrs = onAttrs;
|
||||
// Source: https://github.com/kangax/html-minifier/issues/63
|
||||
// https://html.spec.whatwg.org/#boolean-attribute
|
||||
// https://html.spec.whatwg.org/#attributes-1
|
||||
const htmlBooleanAttributes = new Set(['allowfullscreen', 'allowpaymentrequest', 'allowtransparency', 'async', 'autofocus', 'autoplay', 'checked', 'compact', 'controls', 'declare', 'default', 'defaultchecked', 'defaultmuted', 'defaultselected', 'defer', 'disabled', 'enabled', 'formnovalidate', 'hidden', 'indeterminate', 'inert', 'ismap', 'itemscope', 'loop', 'multiple', 'muted', 'nohref', 'nomodule', 'noresize', 'noshade', 'novalidate', 'nowrap', 'open', 'pauseonexit', 'playsinline', 'readonly', 'required', 'reversed', 'scoped', 'seamless', 'selected', 'sortable', 'truespeed', 'typemustmatch', 'visible']);
|
||||
const amphtmlBooleanAttributes = new Set(['⚡', 'amp', '⚡4ads', 'amp4ads', '⚡4email', 'amp4email', 'amp-custom', 'amp-boilerplate', 'amp4ads-boilerplate', 'amp4email-boilerplate', 'allow-blocked-ranges', 'amp-access-hide', 'amp-access-template', 'amp-keyframes', 'animate', 'arrows', 'data-block-on-consent', 'data-enable-refresh', 'data-multi-size', 'date-template', 'disable-double-tap', 'disable-session-states', 'disableremoteplayback', 'dots', 'expand-single-section', 'expanded', 'fallback', 'first', 'fullscreen', 'inline', 'lightbox', 'noaudio', 'noautoplay', 'noloading', 'once', 'open-after-clear', 'open-after-select', 'open-button', 'placeholder', 'preload', 'reset-on-refresh', 'reset-on-resize', 'resizable', 'rotate-to-fullscreen', 'second', 'standalone', 'stereo', 'submit-error', 'submit-success', 'submitting', 'subscriptions-actions', 'subscriptions-dialog']);
|
||||
const missingValueDefaultEmptyStringAttributes = {
|
||||
// https://html.spec.whatwg.org/#attr-media-preload
|
||||
audio: {
|
||||
preload: 'auto'
|
||||
},
|
||||
video: {
|
||||
preload: 'auto'
|
||||
}
|
||||
};
|
||||
const tagsHasMissingValueDefaultEmptyStringAttributes = new Set(Object.keys(missingValueDefaultEmptyStringAttributes));
|
||||
function onAttrs(options, moduleOptions) {
|
||||
return (attrs, node) => {
|
||||
if (!node.tag) return attrs;
|
||||
const newAttrs = attrs;
|
||||
if (tagsHasMissingValueDefaultEmptyStringAttributes.has(node.tag)) {
|
||||
const tagAttributesCanBeReplacedWithEmptyString = missingValueDefaultEmptyStringAttributes[node.tag];
|
||||
for (const attributesCanBeReplacedWithEmptyString of Object.keys(tagAttributesCanBeReplacedWithEmptyString)) {
|
||||
if (Object.prototype.hasOwnProperty.call(attrs, attributesCanBeReplacedWithEmptyString) && attrs[attributesCanBeReplacedWithEmptyString] === tagAttributesCanBeReplacedWithEmptyString[attributesCanBeReplacedWithEmptyString]) {
|
||||
attrs[attributesCanBeReplacedWithEmptyString] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const attrName of Object.keys(attrs)) {
|
||||
if (attrName === 'visible' && node.tag.startsWith('a-')) {
|
||||
continue;
|
||||
}
|
||||
if (htmlBooleanAttributes.has(attrName)) {
|
||||
newAttrs[attrName] = true;
|
||||
}
|
||||
|
||||
// Fast path optimization.
|
||||
// The rest of tranformations are only for string type attrValue.
|
||||
if (typeof newAttrs[attrName] !== 'string') continue;
|
||||
if (moduleOptions.amphtml && amphtmlBooleanAttributes.has(attrName) && attrs[attrName] === '') {
|
||||
newAttrs[attrName] = true;
|
||||
}
|
||||
// https://html.spec.whatwg.org/#a-quick-introduction-to-html
|
||||
// The value, along with the "=" character, can be omitted altogether if the value is the empty string.
|
||||
if (attrs[attrName] === '') {
|
||||
newAttrs[attrName] = true;
|
||||
}
|
||||
|
||||
// collapse crossorigin attributes
|
||||
// Specification: https://html.spec.whatwg.org/multipage/urls-and-fetching.html#cors-settings-attributes
|
||||
if (attrName.toLowerCase() === 'crossorigin' && attrs[attrName] === 'anonymous') {
|
||||
newAttrs[attrName] = true;
|
||||
}
|
||||
}
|
||||
return newAttrs;
|
||||
};
|
||||
}
|
||||
175
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/collapseBooleanAttributes.mjs
generated
vendored
Normal file
175
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/collapseBooleanAttributes.mjs
generated
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
// Source: https://github.com/kangax/html-minifier/issues/63
|
||||
// https://html.spec.whatwg.org/#boolean-attribute
|
||||
// https://html.spec.whatwg.org/#attributes-1
|
||||
const htmlBooleanAttributes = new Set([
|
||||
'allowfullscreen',
|
||||
'allowpaymentrequest',
|
||||
'allowtransparency',
|
||||
'async',
|
||||
'autofocus',
|
||||
'autoplay',
|
||||
'checked',
|
||||
'compact',
|
||||
'controls',
|
||||
'declare',
|
||||
'default',
|
||||
'defaultchecked',
|
||||
'defaultmuted',
|
||||
'defaultselected',
|
||||
'defer',
|
||||
'disabled',
|
||||
'enabled',
|
||||
'formnovalidate',
|
||||
'hidden',
|
||||
'indeterminate',
|
||||
'inert',
|
||||
'ismap',
|
||||
'itemscope',
|
||||
'loop',
|
||||
'multiple',
|
||||
'muted',
|
||||
'nohref',
|
||||
'nomodule',
|
||||
'noresize',
|
||||
'noshade',
|
||||
'novalidate',
|
||||
'nowrap',
|
||||
'open',
|
||||
'pauseonexit',
|
||||
'playsinline',
|
||||
'readonly',
|
||||
'required',
|
||||
'reversed',
|
||||
'scoped',
|
||||
'seamless',
|
||||
'selected',
|
||||
'sortable',
|
||||
'truespeed',
|
||||
'typemustmatch',
|
||||
'visible'
|
||||
]);
|
||||
|
||||
const amphtmlBooleanAttributes = new Set([
|
||||
'⚡',
|
||||
'amp',
|
||||
'⚡4ads',
|
||||
'amp4ads',
|
||||
'⚡4email',
|
||||
'amp4email',
|
||||
|
||||
'amp-custom',
|
||||
'amp-boilerplate',
|
||||
'amp4ads-boilerplate',
|
||||
'amp4email-boilerplate',
|
||||
|
||||
'allow-blocked-ranges',
|
||||
'amp-access-hide',
|
||||
'amp-access-template',
|
||||
'amp-keyframes',
|
||||
'animate',
|
||||
'arrows',
|
||||
'data-block-on-consent',
|
||||
'data-enable-refresh',
|
||||
'data-multi-size',
|
||||
'date-template',
|
||||
'disable-double-tap',
|
||||
'disable-session-states',
|
||||
'disableremoteplayback',
|
||||
'dots',
|
||||
'expand-single-section',
|
||||
'expanded',
|
||||
'fallback',
|
||||
'first',
|
||||
'fullscreen',
|
||||
'inline',
|
||||
'lightbox',
|
||||
'noaudio',
|
||||
'noautoplay',
|
||||
'noloading',
|
||||
'once',
|
||||
'open-after-clear',
|
||||
'open-after-select',
|
||||
'open-button',
|
||||
'placeholder',
|
||||
'preload',
|
||||
'reset-on-refresh',
|
||||
'reset-on-resize',
|
||||
'resizable',
|
||||
'rotate-to-fullscreen',
|
||||
'second',
|
||||
'standalone',
|
||||
'stereo',
|
||||
'submit-error',
|
||||
'submit-success',
|
||||
'submitting',
|
||||
'subscriptions-actions',
|
||||
'subscriptions-dialog'
|
||||
]);
|
||||
|
||||
const missingValueDefaultEmptyStringAttributes = {
|
||||
// https://html.spec.whatwg.org/#attr-media-preload
|
||||
audio: {
|
||||
preload: 'auto'
|
||||
},
|
||||
video: {
|
||||
preload: 'auto'
|
||||
}
|
||||
};
|
||||
|
||||
const tagsHasMissingValueDefaultEmptyStringAttributes = new Set(Object.keys(missingValueDefaultEmptyStringAttributes));
|
||||
|
||||
export function onAttrs(options, moduleOptions) {
|
||||
return (attrs, node) => {
|
||||
if (!node.tag) return attrs;
|
||||
|
||||
const newAttrs = attrs;
|
||||
|
||||
if (tagsHasMissingValueDefaultEmptyStringAttributes.has(node.tag)) {
|
||||
const tagAttributesCanBeReplacedWithEmptyString = missingValueDefaultEmptyStringAttributes[node.tag];
|
||||
|
||||
for (const attributesCanBeReplacedWithEmptyString of Object.keys(tagAttributesCanBeReplacedWithEmptyString)) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(attrs, attributesCanBeReplacedWithEmptyString)
|
||||
&& attrs[attributesCanBeReplacedWithEmptyString] === tagAttributesCanBeReplacedWithEmptyString[attributesCanBeReplacedWithEmptyString]
|
||||
) {
|
||||
attrs[attributesCanBeReplacedWithEmptyString] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const attrName of Object.keys(attrs)) {
|
||||
if (attrName === 'visible' && node.tag.startsWith('a-')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (htmlBooleanAttributes.has(attrName)) {
|
||||
newAttrs[attrName] = true;
|
||||
}
|
||||
|
||||
// Fast path optimization.
|
||||
// The rest of tranformations are only for string type attrValue.
|
||||
if (typeof newAttrs[attrName] !== 'string') continue;
|
||||
|
||||
if (moduleOptions.amphtml && amphtmlBooleanAttributes.has(attrName) && attrs[attrName] === '') {
|
||||
newAttrs[attrName] = true;
|
||||
}
|
||||
// https://html.spec.whatwg.org/#a-quick-introduction-to-html
|
||||
// The value, along with the "=" character, can be omitted altogether if the value is the empty string.
|
||||
if (attrs[attrName] === '') {
|
||||
newAttrs[attrName] = true;
|
||||
}
|
||||
|
||||
// collapse crossorigin attributes
|
||||
// Specification: https://html.spec.whatwg.org/multipage/urls-and-fetching.html#cors-settings-attributes
|
||||
if (
|
||||
attrName.toLowerCase() === 'crossorigin' && (
|
||||
attrs[attrName] === 'anonymous'
|
||||
)
|
||||
) {
|
||||
newAttrs[attrName] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return newAttrs;
|
||||
};
|
||||
}
|
||||
100
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/collapseWhitespace.cjs
generated
vendored
Normal file
100
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/collapseWhitespace.cjs
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = collapseWhitespace;
|
||||
var _helpers = require("../helpers.cjs");
|
||||
const noWhitespaceCollapseElements = new Set(['script', 'style', 'pre', 'textarea']);
|
||||
const noTrimWhitespacesArroundElements = new Set([
|
||||
// non-empty tags that will maintain whitespace around them
|
||||
'a', 'abbr', 'acronym', 'b', 'bdi', 'bdo', 'big', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'ins', 'kbd', 'label', 'mark', 'math', 'nobr', 'object', 'q', 'rp', 'rt', 'rtc', 'ruby', 's', 'samp', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'svg', 'textarea', 'time', 'tt', 'u', 'var',
|
||||
// self-closing tags that will maintain whitespace around them
|
||||
'comment', 'img', 'input', 'wbr']);
|
||||
const noTrimWhitespacesInsideElements = new Set([
|
||||
// non-empty tags that will maintain whitespace within them
|
||||
'a', 'abbr', 'acronym', 'b', 'big', 'del', 'em', 'font', 'i', 'ins', 'kbd', 'mark', 'nobr', 'rp', 's', 'samp', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'time', 'tt', 'u', 'var']);
|
||||
const startsWithWhitespacePattern = /^\s/;
|
||||
const endsWithWhitespacePattern = /\s$/;
|
||||
// See https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace and https://infra.spec.whatwg.org/#ascii-whitespace
|
||||
const multipleWhitespacePattern = /[\t\n\f\r ]+/g;
|
||||
const NONE = '';
|
||||
const SINGLE_SPACE = ' ';
|
||||
const validOptions = ['all', 'aggressive', 'conservative'];
|
||||
|
||||
/** Collapses redundant whitespaces */
|
||||
function collapseWhitespace(tree, options, collapseType, parent) {
|
||||
collapseType = validOptions.includes(collapseType) ? collapseType : 'conservative';
|
||||
tree.forEach((node, index) => {
|
||||
const prevNode = tree[index - 1];
|
||||
const nextNode = tree[index + 1];
|
||||
if (typeof node === 'string') {
|
||||
const parentNodeTag = parent && parent.node && parent.node.tag;
|
||||
const isTopLevel = !parentNodeTag || parentNodeTag === 'html' || parentNodeTag === 'head';
|
||||
const shouldTrim = collapseType === 'all' || isTopLevel ||
|
||||
/*
|
||||
* When collapseType is set to 'aggressive', and the tag is not inside 'noTrimWhitespacesInsideElements'.
|
||||
* the first & last space inside the tag will be trimmed
|
||||
*/
|
||||
collapseType === 'aggressive';
|
||||
node = collapseRedundantWhitespaces(node, collapseType, shouldTrim, parent, prevNode, nextNode);
|
||||
}
|
||||
const isAllowCollapseWhitespace = !noWhitespaceCollapseElements.has(node.tag);
|
||||
if (node.content && node.content.length && isAllowCollapseWhitespace) {
|
||||
node.content = collapseWhitespace(node.content, options, collapseType, {
|
||||
node,
|
||||
prevNode,
|
||||
nextNode
|
||||
});
|
||||
}
|
||||
tree[index] = node;
|
||||
});
|
||||
return tree;
|
||||
}
|
||||
function collapseRedundantWhitespaces(text, collapseType, shouldTrim = false, parent, prevNode, nextNode) {
|
||||
if (!text || text.length === 0) {
|
||||
return NONE;
|
||||
}
|
||||
if (!(0, _helpers.isComment)(text)) {
|
||||
text = text.replace(multipleWhitespacePattern, SINGLE_SPACE);
|
||||
}
|
||||
if (shouldTrim) {
|
||||
if (collapseType === 'aggressive') {
|
||||
if (!noTrimWhitespacesInsideElements.has(parent && parent.node && parent.node.tag)) {
|
||||
if (
|
||||
// It is the first child node of the parent
|
||||
!prevNode
|
||||
// It is not the first child node, and prevNode not a text node, and prevNode is safe to trim around
|
||||
|| prevNode && prevNode.tag && !noTrimWhitespacesArroundElements.has(prevNode.tag)) {
|
||||
text = text.trimStart();
|
||||
} else {
|
||||
// previous node is a "no trim whitespaces arround element"
|
||||
if (
|
||||
// but previous node ends with a whitespace
|
||||
prevNode && prevNode.content && prevNode.content.length && endsWithWhitespacePattern.test(prevNode.content[prevNode.content.length - 1]) && (!nextNode // either the current node is the last child of the parent
|
||||
||
|
||||
// or the next node starts with a white space
|
||||
nextNode && nextNode.content && nextNode.content.length && !startsWithWhitespacePattern.test(nextNode.content[0]))) {
|
||||
text = text.trimStart();
|
||||
}
|
||||
}
|
||||
if (!nextNode || nextNode && nextNode.tag && !noTrimWhitespacesArroundElements.has(nextNode.tag)) {
|
||||
text = text.trimEnd();
|
||||
}
|
||||
} else {
|
||||
// now it is a textNode inside a "no trim whitespaces inside elements" node
|
||||
if (!prevNode // it the textnode is the first child of the node
|
||||
&& startsWithWhitespacePattern.test(text[0]) // it starts with white space
|
||||
&& typeof parent.prevNode === 'string' // the prev of the node is a textNode as well
|
||||
&& endsWithWhitespacePattern.test(parent.prevNode[parent.prevNode.length - 1]) // that prev is ends with a white
|
||||
) {
|
||||
text = text.trimStart();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// collapseType is 'all', trim spaces
|
||||
text = text.trim();
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
132
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/collapseWhitespace.mjs
generated
vendored
Normal file
132
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/collapseWhitespace.mjs
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
import { isComment } from '../helpers.mjs';
|
||||
|
||||
const noWhitespaceCollapseElements = new Set([
|
||||
'script',
|
||||
'style',
|
||||
'pre',
|
||||
'textarea'
|
||||
]);
|
||||
|
||||
const noTrimWhitespacesArroundElements = new Set([
|
||||
// non-empty tags that will maintain whitespace around them
|
||||
'a', 'abbr', 'acronym', 'b', 'bdi', 'bdo', 'big', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'ins', 'kbd', 'label', 'mark', 'math', 'nobr', 'object', 'q', 'rp', 'rt', 'rtc', 'ruby', 's', 'samp', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'svg', 'textarea', 'time', 'tt', 'u', 'var',
|
||||
// self-closing tags that will maintain whitespace around them
|
||||
'comment', 'img', 'input', 'wbr'
|
||||
]);
|
||||
|
||||
const noTrimWhitespacesInsideElements = new Set([
|
||||
// non-empty tags that will maintain whitespace within them
|
||||
'a', 'abbr', 'acronym', 'b', 'big', 'del', 'em', 'font', 'i', 'ins', 'kbd', 'mark', 'nobr', 'rp', 's', 'samp', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'time', 'tt', 'u', 'var'
|
||||
]);
|
||||
|
||||
const startsWithWhitespacePattern = /^\s/;
|
||||
const endsWithWhitespacePattern = /\s$/;
|
||||
// See https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace and https://infra.spec.whatwg.org/#ascii-whitespace
|
||||
const multipleWhitespacePattern = /[\t\n\f\r ]+/g;
|
||||
const NONE = '';
|
||||
const SINGLE_SPACE = ' ';
|
||||
const validOptions = ['all', 'aggressive', 'conservative'];
|
||||
|
||||
/** Collapses redundant whitespaces */
|
||||
export default function collapseWhitespace(tree, options, collapseType, parent) {
|
||||
collapseType = validOptions.includes(collapseType) ? collapseType : 'conservative';
|
||||
|
||||
tree.forEach((node, index) => {
|
||||
const prevNode = tree[index - 1];
|
||||
const nextNode = tree[index + 1];
|
||||
|
||||
if (typeof node === 'string') {
|
||||
const parentNodeTag = parent && parent.node && parent.node.tag;
|
||||
const isTopLevel = !parentNodeTag || parentNodeTag === 'html' || parentNodeTag === 'head';
|
||||
const shouldTrim = (
|
||||
collapseType === 'all' ||
|
||||
isTopLevel ||
|
||||
/*
|
||||
* When collapseType is set to 'aggressive', and the tag is not inside 'noTrimWhitespacesInsideElements'.
|
||||
* the first & last space inside the tag will be trimmed
|
||||
*/
|
||||
collapseType === 'aggressive'
|
||||
);
|
||||
|
||||
node = collapseRedundantWhitespaces(node, collapseType, shouldTrim, parent, prevNode, nextNode);
|
||||
}
|
||||
|
||||
const isAllowCollapseWhitespace = !noWhitespaceCollapseElements.has(node.tag);
|
||||
if (node.content && node.content.length && isAllowCollapseWhitespace) {
|
||||
node.content = collapseWhitespace(node.content, options, collapseType, {
|
||||
node,
|
||||
prevNode,
|
||||
nextNode
|
||||
});
|
||||
}
|
||||
|
||||
tree[index] = node;
|
||||
});
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
|
||||
function collapseRedundantWhitespaces(text, collapseType, shouldTrim = false, parent, prevNode, nextNode) {
|
||||
if (!text || text.length === 0) {
|
||||
return NONE;
|
||||
}
|
||||
|
||||
if (!isComment(text)) {
|
||||
text = text.replace(multipleWhitespacePattern, SINGLE_SPACE);
|
||||
}
|
||||
|
||||
if (shouldTrim) {
|
||||
if (collapseType === 'aggressive') {
|
||||
if (!noTrimWhitespacesInsideElements.has(parent && parent.node && parent.node.tag)) {
|
||||
if (
|
||||
// It is the first child node of the parent
|
||||
!prevNode
|
||||
// It is not the first child node, and prevNode not a text node, and prevNode is safe to trim around
|
||||
|| prevNode && prevNode.tag && !noTrimWhitespacesArroundElements.has(prevNode.tag)
|
||||
) {
|
||||
text = text.trimStart();
|
||||
} else {
|
||||
// previous node is a "no trim whitespaces arround element"
|
||||
if (
|
||||
// but previous node ends with a whitespace
|
||||
prevNode && prevNode.content && prevNode.content.length
|
||||
&& endsWithWhitespacePattern.test(prevNode.content[prevNode.content.length - 1])
|
||||
&& (
|
||||
!nextNode // either the current node is the last child of the parent
|
||||
|| (
|
||||
// or the next node starts with a white space
|
||||
nextNode && nextNode.content && nextNode.content.length
|
||||
&& !startsWithWhitespacePattern.test(nextNode.content[0])
|
||||
)
|
||||
)
|
||||
) {
|
||||
text = text.trimStart();
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
!nextNode
|
||||
|| nextNode && nextNode.tag && !noTrimWhitespacesArroundElements.has(nextNode.tag)
|
||||
) {
|
||||
text = text.trimEnd();
|
||||
}
|
||||
} else {
|
||||
// now it is a textNode inside a "no trim whitespaces inside elements" node
|
||||
if (
|
||||
!prevNode // it the textnode is the first child of the node
|
||||
&& startsWithWhitespacePattern.test(text[0]) // it starts with white space
|
||||
&& typeof parent.prevNode === 'string' // the prev of the node is a textNode as well
|
||||
&& endsWithWhitespacePattern.test(parent.prevNode[parent.prevNode.length - 1]) // that prev is ends with a white
|
||||
) {
|
||||
text = text.trimStart();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// collapseType is 'all', trim spaces
|
||||
text = text.trim();
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
19
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/custom.cjs
generated
vendored
Normal file
19
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/custom.cjs
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = custom;
|
||||
/** Meta-module that runs custom modules */
|
||||
function custom(tree, options, customModules) {
|
||||
if (!customModules) {
|
||||
return tree;
|
||||
}
|
||||
if (!Array.isArray(customModules)) {
|
||||
customModules = [customModules];
|
||||
}
|
||||
customModules.forEach(customModule => {
|
||||
tree = customModule(tree, options);
|
||||
});
|
||||
return tree;
|
||||
}
|
||||
16
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/custom.mjs
generated
vendored
Normal file
16
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/custom.mjs
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
/** Meta-module that runs custom modules */
|
||||
export default function custom(tree, options, customModules) {
|
||||
if (! customModules) {
|
||||
return tree;
|
||||
}
|
||||
|
||||
if (! Array.isArray(customModules)) {
|
||||
customModules = [customModules];
|
||||
}
|
||||
|
||||
customModules.forEach(customModule => {
|
||||
tree = customModule(tree, options);
|
||||
});
|
||||
|
||||
return tree;
|
||||
}
|
||||
38
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/deduplicateAttributeValues.cjs
generated
vendored
Normal file
38
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/deduplicateAttributeValues.cjs
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.onAttrs = onAttrs;
|
||||
var _collapseAttributeWhitespace = require("./collapseAttributeWhitespace.cjs");
|
||||
/** Deduplicate values inside list-like attributes (e.g. class, rel) */
|
||||
function onAttrs() {
|
||||
return attrs => {
|
||||
const newAttrs = attrs;
|
||||
Object.keys(attrs).forEach(attrName => {
|
||||
if (!_collapseAttributeWhitespace.attributesWithLists.has(attrName)) {
|
||||
return;
|
||||
}
|
||||
if (typeof attrs[attrName] !== 'string') {
|
||||
return;
|
||||
}
|
||||
const attrValues = attrs[attrName].split(/\s/);
|
||||
const uniqeAttrValues = new Set();
|
||||
const deduplicatedAttrValues = [];
|
||||
attrValues.forEach(attrValue => {
|
||||
if (!attrValue) {
|
||||
// Keep whitespaces
|
||||
deduplicatedAttrValues.push('');
|
||||
return;
|
||||
}
|
||||
if (uniqeAttrValues.has(attrValue)) {
|
||||
return;
|
||||
}
|
||||
deduplicatedAttrValues.push(attrValue);
|
||||
uniqeAttrValues.add(attrValue);
|
||||
});
|
||||
newAttrs[attrName] = deduplicatedAttrValues.join(' ');
|
||||
});
|
||||
return newAttrs;
|
||||
};
|
||||
}
|
||||
40
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/deduplicateAttributeValues.mjs
generated
vendored
Normal file
40
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/deduplicateAttributeValues.mjs
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
import { attributesWithLists } from './collapseAttributeWhitespace.mjs';
|
||||
|
||||
/** Deduplicate values inside list-like attributes (e.g. class, rel) */
|
||||
export function onAttrs() {
|
||||
return (attrs) => {
|
||||
const newAttrs = attrs;
|
||||
Object.keys(attrs).forEach(attrName => {
|
||||
if (! attributesWithLists.has(attrName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof attrs[attrName] !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
const attrValues = attrs[attrName].split(/\s/);
|
||||
const uniqeAttrValues = new Set();
|
||||
const deduplicatedAttrValues = [];
|
||||
|
||||
attrValues.forEach((attrValue) => {
|
||||
if (! attrValue) {
|
||||
// Keep whitespaces
|
||||
deduplicatedAttrValues.push('');
|
||||
return;
|
||||
}
|
||||
|
||||
if (uniqeAttrValues.has(attrValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
deduplicatedAttrValues.push(attrValue);
|
||||
uniqeAttrValues.add(attrValue);
|
||||
});
|
||||
|
||||
newAttrs[attrName] = deduplicatedAttrValues.join(' ');
|
||||
});
|
||||
|
||||
return newAttrs;
|
||||
};
|
||||
}
|
||||
85
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/example.cjs
generated
vendored
Normal file
85
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/example.cjs
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = example;
|
||||
exports.onAttrs = onAttrs;
|
||||
exports.onContent = onContent;
|
||||
exports.onNode = onNode;
|
||||
/**
|
||||
* It is an example htmlnano module.
|
||||
*
|
||||
* A htmlnano module can be modify the attributes of every node (through a "onAttrs" named export),
|
||||
* modify the content of every node (through an optional "onContent" named export), modify the node
|
||||
* itself (through an optional "onNode" named export), or modify the entire tree (through an optional
|
||||
* default export).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Modify attributes of node. Optional.
|
||||
*
|
||||
* @param {object} options - Options that were passed to htmlnano
|
||||
* @param moduleOptions — Module options. For most modules this is just "true" (indication that the module was enabled)
|
||||
* @return {Function} - Return a function that takes attribute object and the node (for the context), and returns the modified attribute object
|
||||
*/
|
||||
function onAttrs(options, moduleOptions) {
|
||||
return (attrs, node) => {
|
||||
// You can modify "attrs" based on "node"
|
||||
const newAttrs = {
|
||||
...attrs
|
||||
};
|
||||
return newAttrs; // ... then return the modified attrs
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify content of node. Optional.
|
||||
*
|
||||
* @param {object} options - Options that were passed to htmlnano
|
||||
* @param moduleOptions — Module options. For most modules this is just "true" (indication that the module was enabled)
|
||||
* @return {Function} - Return a function that takes contents (an array of node and string) and the node (for the context), and returns the modified content array.
|
||||
*/
|
||||
function onContent(options, moduleOptions) {
|
||||
return (content, node) => {
|
||||
// Same goes the "content"
|
||||
|
||||
return content; // ... return modified content here
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* It is possible to modify entire ndde as well. Optional.
|
||||
* @param {object} options - Options that were passed to htmlnano
|
||||
* @param moduleOptions — Module options. For most modules this is just "true" (indication that the module was enabled)
|
||||
* @return {Function} - Return a function that takes the node, and returns the new, modified node.
|
||||
*/
|
||||
function onNode(options, moduleOptions) {
|
||||
return node => {
|
||||
return node; // ... return new node here
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the entire tree. Optional.
|
||||
*
|
||||
* @param {object} tree - PostHTML tree (https://github.com/posthtml/posthtml/blob/master/README.md)
|
||||
* @param {object} options - Options that were passed to htmlnano
|
||||
* @param moduleOptions — Module options. For most modules this is just "true" (indication that the module was enabled)
|
||||
* @return {object | Proimse} - Return the modified tree.
|
||||
*/
|
||||
function example(tree, options, moduleOptions) {
|
||||
// Module filename (example.es6), exported default function name (example),
|
||||
// and test filename (example.js) must be the same.
|
||||
|
||||
// You can traverse the tree...
|
||||
tree.walk(node => {
|
||||
// ...and make some minification
|
||||
});
|
||||
|
||||
// At the end you must return the tree
|
||||
return tree;
|
||||
|
||||
// Or a promise with the tree
|
||||
return somePromise.then(() => tree);
|
||||
}
|
||||
75
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/example.mjs
generated
vendored
Normal file
75
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/example.mjs
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* It is an example htmlnano module.
|
||||
*
|
||||
* A htmlnano module can be modify the attributes of every node (through a "onAttrs" named export),
|
||||
* modify the content of every node (through an optional "onContent" named export), modify the node
|
||||
* itself (through an optional "onNode" named export), or modify the entire tree (through an optional
|
||||
* default export).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Modify attributes of node. Optional.
|
||||
*
|
||||
* @param {object} options - Options that were passed to htmlnano
|
||||
* @param moduleOptions — Module options. For most modules this is just "true" (indication that the module was enabled)
|
||||
* @return {Function} - Return a function that takes attribute object and the node (for the context), and returns the modified attribute object
|
||||
*/
|
||||
export function onAttrs(options, moduleOptions) {
|
||||
return (attrs, node) => {
|
||||
// You can modify "attrs" based on "node"
|
||||
const newAttrs = { ...attrs };
|
||||
|
||||
return newAttrs; // ... then return the modified attrs
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify content of node. Optional.
|
||||
*
|
||||
* @param {object} options - Options that were passed to htmlnano
|
||||
* @param moduleOptions — Module options. For most modules this is just "true" (indication that the module was enabled)
|
||||
* @return {Function} - Return a function that takes contents (an array of node and string) and the node (for the context), and returns the modified content array.
|
||||
*/
|
||||
export function onContent(options, moduleOptions) {
|
||||
return (content, node) => {
|
||||
// Same goes the "content"
|
||||
|
||||
return content; // ... return modified content here
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* It is possible to modify entire ndde as well. Optional.
|
||||
* @param {object} options - Options that were passed to htmlnano
|
||||
* @param moduleOptions — Module options. For most modules this is just "true" (indication that the module was enabled)
|
||||
* @return {Function} - Return a function that takes the node, and returns the new, modified node.
|
||||
*/
|
||||
export function onNode(options, moduleOptions) {
|
||||
return (node) => {
|
||||
return node; // ... return new node here
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the entire tree. Optional.
|
||||
*
|
||||
* @param {object} tree - PostHTML tree (https://github.com/posthtml/posthtml/blob/master/README.md)
|
||||
* @param {object} options - Options that were passed to htmlnano
|
||||
* @param moduleOptions — Module options. For most modules this is just "true" (indication that the module was enabled)
|
||||
* @return {object | Proimse} - Return the modified tree.
|
||||
*/
|
||||
export default function example(tree, options, moduleOptions) {
|
||||
// Module filename (example.es6), exported default function name (example),
|
||||
// and test filename (example.js) must be the same.
|
||||
|
||||
// You can traverse the tree...
|
||||
tree.walk(node => {
|
||||
// ...and make some minification
|
||||
});
|
||||
|
||||
// At the end you must return the tree
|
||||
return tree;
|
||||
|
||||
// Or a promise with the tree
|
||||
return somePromise.then(() => tree);
|
||||
}
|
||||
54
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/mergeScripts.cjs
generated
vendored
Normal file
54
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/mergeScripts.cjs
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = mergeScripts;
|
||||
/* Merge multiple <script> into one */
|
||||
function mergeScripts(tree) {
|
||||
let scriptNodesIndex = {};
|
||||
let scriptSrcIndex = 1;
|
||||
tree.match({
|
||||
tag: 'script'
|
||||
}, node => {
|
||||
const nodeAttrs = node.attrs || {};
|
||||
if ('src' in nodeAttrs
|
||||
// Skip SRI, reasons are documented in "minifyJs" module
|
||||
|| 'integrity' in nodeAttrs) {
|
||||
scriptSrcIndex++;
|
||||
return node;
|
||||
}
|
||||
const scriptType = nodeAttrs.type || 'text/javascript';
|
||||
if (scriptType !== 'text/javascript' && scriptType !== 'application/javascript') {
|
||||
return node;
|
||||
}
|
||||
const scriptKey = JSON.stringify({
|
||||
id: nodeAttrs.id,
|
||||
class: nodeAttrs.class,
|
||||
type: scriptType,
|
||||
defer: nodeAttrs.defer !== undefined,
|
||||
async: nodeAttrs.async !== undefined,
|
||||
index: scriptSrcIndex
|
||||
});
|
||||
if (!scriptNodesIndex[scriptKey]) {
|
||||
scriptNodesIndex[scriptKey] = [];
|
||||
}
|
||||
scriptNodesIndex[scriptKey].push(node);
|
||||
return node;
|
||||
});
|
||||
for (const scriptNodes of Object.values(scriptNodesIndex)) {
|
||||
let lastScriptNode = scriptNodes.pop();
|
||||
scriptNodes.reverse().forEach(scriptNode => {
|
||||
let scriptContent = (scriptNode.content || []).join(' ');
|
||||
scriptContent = scriptContent.trim();
|
||||
if (scriptContent.slice(-1) !== ';') {
|
||||
scriptContent += ';';
|
||||
}
|
||||
lastScriptNode.content = lastScriptNode.content || [];
|
||||
lastScriptNode.content.unshift(scriptContent);
|
||||
scriptNode.tag = false;
|
||||
scriptNode.content = [];
|
||||
});
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
56
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/mergeScripts.mjs
generated
vendored
Normal file
56
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/mergeScripts.mjs
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
/* Merge multiple <script> into one */
|
||||
export default function mergeScripts (tree) {
|
||||
let scriptNodesIndex = {};
|
||||
let scriptSrcIndex = 1;
|
||||
|
||||
tree.match({ tag: 'script' }, node => {
|
||||
const nodeAttrs = node.attrs || {};
|
||||
if (
|
||||
'src' in nodeAttrs
|
||||
// Skip SRI, reasons are documented in "minifyJs" module
|
||||
|| 'integrity' in nodeAttrs
|
||||
) {
|
||||
scriptSrcIndex++;
|
||||
return node;
|
||||
}
|
||||
|
||||
const scriptType = nodeAttrs.type || 'text/javascript';
|
||||
if (scriptType !== 'text/javascript' && scriptType !== 'application/javascript') {
|
||||
return node;
|
||||
}
|
||||
|
||||
const scriptKey = JSON.stringify({
|
||||
id: nodeAttrs.id,
|
||||
class: nodeAttrs.class,
|
||||
type: scriptType,
|
||||
defer: nodeAttrs.defer !== undefined,
|
||||
async: nodeAttrs.async !== undefined,
|
||||
index: scriptSrcIndex,
|
||||
});
|
||||
if (!scriptNodesIndex[scriptKey]) {
|
||||
scriptNodesIndex[scriptKey] = [];
|
||||
}
|
||||
|
||||
scriptNodesIndex[scriptKey].push(node);
|
||||
return node;
|
||||
});
|
||||
|
||||
for (const scriptNodes of Object.values(scriptNodesIndex)) {
|
||||
let lastScriptNode = scriptNodes.pop();
|
||||
scriptNodes.reverse().forEach(scriptNode => {
|
||||
let scriptContent = (scriptNode.content || []).join(' ');
|
||||
scriptContent = scriptContent.trim();
|
||||
if (scriptContent.slice(-1) !== ';') {
|
||||
scriptContent += ';';
|
||||
}
|
||||
|
||||
lastScriptNode.content = lastScriptNode.content || [];
|
||||
lastScriptNode.content.unshift(scriptContent);
|
||||
|
||||
scriptNode.tag = false;
|
||||
scriptNode.content = [];
|
||||
});
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
38
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/mergeStyles.cjs
generated
vendored
Normal file
38
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/mergeStyles.cjs
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = mergeStyles;
|
||||
var _helpers = require("../helpers.cjs");
|
||||
/* Merge multiple <style> into one */
|
||||
function mergeStyles(tree) {
|
||||
const styleNodes = {};
|
||||
tree.match({
|
||||
tag: 'style'
|
||||
}, node => {
|
||||
const nodeAttrs = node.attrs || {};
|
||||
// Skip <style scoped></style>
|
||||
// https://developer.mozilla.org/en/docs/Web/HTML/Element/style
|
||||
//
|
||||
// Also skip SRI, reasons are documented in "minifyJs" module
|
||||
if ('scoped' in nodeAttrs || 'integrity' in nodeAttrs) {
|
||||
return node;
|
||||
}
|
||||
if ((0, _helpers.isAmpBoilerplate)(node)) {
|
||||
return node;
|
||||
}
|
||||
const styleType = nodeAttrs.type || 'text/css';
|
||||
const styleMedia = nodeAttrs.media || 'all';
|
||||
const styleKey = styleType + '_' + styleMedia;
|
||||
if (styleNodes[styleKey]) {
|
||||
const styleContent = (node.content || []).join(' ');
|
||||
styleNodes[styleKey].content.push(' ' + styleContent);
|
||||
return '';
|
||||
}
|
||||
node.content = node.content || [];
|
||||
styleNodes[styleKey] = node;
|
||||
return node;
|
||||
});
|
||||
return tree;
|
||||
}
|
||||
36
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/mergeStyles.mjs
generated
vendored
Normal file
36
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/mergeStyles.mjs
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
import { isAmpBoilerplate } from '../helpers.mjs';
|
||||
|
||||
/* Merge multiple <style> into one */
|
||||
export default function mergeStyles(tree) {
|
||||
const styleNodes = {};
|
||||
|
||||
tree.match({tag: 'style'}, node => {
|
||||
const nodeAttrs = node.attrs || {};
|
||||
// Skip <style scoped></style>
|
||||
// https://developer.mozilla.org/en/docs/Web/HTML/Element/style
|
||||
//
|
||||
// Also skip SRI, reasons are documented in "minifyJs" module
|
||||
if ('scoped' in nodeAttrs || 'integrity' in nodeAttrs) {
|
||||
return node;
|
||||
}
|
||||
|
||||
if (isAmpBoilerplate(node)) {
|
||||
return node;
|
||||
}
|
||||
|
||||
const styleType = nodeAttrs.type || 'text/css';
|
||||
const styleMedia = nodeAttrs.media || 'all';
|
||||
const styleKey = styleType + '_' + styleMedia;
|
||||
if (styleNodes[styleKey]) {
|
||||
const styleContent = (node.content || []).join(' ');
|
||||
styleNodes[styleKey].content.push(' ' + styleContent);
|
||||
return '';
|
||||
}
|
||||
|
||||
node.content = node.content || [];
|
||||
styleNodes[styleKey] = node;
|
||||
return node;
|
||||
});
|
||||
|
||||
return tree;
|
||||
}
|
||||
47
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyConditionalComments.cjs
generated
vendored
Normal file
47
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyConditionalComments.cjs
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = minifyConditionalComments;
|
||||
var _htmlnano = _interopRequireDefault(require("../htmlnano.cjs"));
|
||||
var _helpers = require("../helpers.cjs");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
// Spec: https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/compatibility/ms537512(v=vs.85)
|
||||
const CONDITIONAL_COMMENT_REGEXP = /(<!--\[if\s+?[^<>[\]]+?]>)([\s\S]+?)(<!\[endif\]-->)/gm;
|
||||
|
||||
/** Minify content inside conditional comments */
|
||||
async function minifyConditionalComments(tree, htmlnanoOptions) {
|
||||
// forEach, tree.walk, tree.match just don't support Promise.
|
||||
for (let i = 0, len = tree.length; i < len; i++) {
|
||||
const node = tree[i];
|
||||
if (typeof node === 'string' && (0, _helpers.isConditionalComment)(node)) {
|
||||
tree[i] = await minifycontentInsideConditionalComments(node, htmlnanoOptions);
|
||||
}
|
||||
if (node.content && node.content.length) {
|
||||
tree[i].content = await minifyConditionalComments(node.content, htmlnanoOptions);
|
||||
}
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
async function minifycontentInsideConditionalComments(text, htmlnanoOptions) {
|
||||
let match;
|
||||
const matches = [];
|
||||
|
||||
// FIXME!
|
||||
// String#matchAll is supported since Node.js 12
|
||||
while ((match = CONDITIONAL_COMMENT_REGEXP.exec(text)) !== null) {
|
||||
matches.push([match[1], match[2], match[3]]);
|
||||
}
|
||||
if (!matches.length) {
|
||||
return Promise.resolve(text);
|
||||
}
|
||||
return Promise.all(matches.map(async match => {
|
||||
const result = await _htmlnano.default.process(match[1], htmlnanoOptions, {}, {});
|
||||
let minified = result.html;
|
||||
if (match[1].includes('<html') && minified.includes('</html>')) {
|
||||
minified = minified.replace('</html>', '');
|
||||
}
|
||||
return match[0] + minified + match[2];
|
||||
}));
|
||||
}
|
||||
49
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyConditionalComments.mjs
generated
vendored
Normal file
49
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyConditionalComments.mjs
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
import htmlnano from '../htmlnano.mjs';
|
||||
import { isConditionalComment } from '../helpers.mjs';
|
||||
|
||||
// Spec: https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/compatibility/ms537512(v=vs.85)
|
||||
const CONDITIONAL_COMMENT_REGEXP = /(<!--\[if\s+?[^<>[\]]+?]>)([\s\S]+?)(<!\[endif\]-->)/gm;
|
||||
|
||||
/** Minify content inside conditional comments */
|
||||
export default async function minifyConditionalComments(tree, htmlnanoOptions) {
|
||||
// forEach, tree.walk, tree.match just don't support Promise.
|
||||
for (let i = 0, len = tree.length; i < len; i++) {
|
||||
const node = tree[i];
|
||||
|
||||
if (typeof node === 'string' && isConditionalComment(node)) {
|
||||
tree[i] = await minifycontentInsideConditionalComments(node, htmlnanoOptions);
|
||||
}
|
||||
|
||||
if (node.content && node.content.length) {
|
||||
tree[i].content = await minifyConditionalComments(node.content, htmlnanoOptions);
|
||||
}
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
async function minifycontentInsideConditionalComments(text, htmlnanoOptions) {
|
||||
let match;
|
||||
const matches = [];
|
||||
|
||||
// FIXME!
|
||||
// String#matchAll is supported since Node.js 12
|
||||
while ((match = CONDITIONAL_COMMENT_REGEXP.exec(text)) !== null) {
|
||||
matches.push([match[1], match[2], match[3]]);
|
||||
}
|
||||
|
||||
if (!matches.length) {
|
||||
return Promise.resolve(text);
|
||||
}
|
||||
|
||||
return Promise.all(matches.map(async match => {
|
||||
const result = await htmlnano.process(match[1], htmlnanoOptions, {}, {});
|
||||
let minified = result.html;
|
||||
|
||||
if (match[1].includes('<html') && minified.includes('</html>')) {
|
||||
minified = minified.replace('</html>', '');
|
||||
}
|
||||
|
||||
return match[0] + minified + match[2];
|
||||
}));
|
||||
}
|
||||
73
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyCss.cjs
generated
vendored
Normal file
73
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyCss.cjs
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = minifyCss;
|
||||
var _helpers = require("../helpers.cjs");
|
||||
const postcssOptions = {
|
||||
// Prevent the following warning from being shown:
|
||||
// > Without `from` option PostCSS could generate wrong source map and will not find Browserslist config.
|
||||
// > Set it to CSS file path or to `undefined` to prevent this warning.
|
||||
from: undefined
|
||||
};
|
||||
|
||||
/** Minify CSS with cssnano */
|
||||
async function minifyCss(tree, options, cssnanoOptions) {
|
||||
const cssnano = await (0, _helpers.optionalImport)('cssnano');
|
||||
const postcss = await (0, _helpers.optionalImport)('postcss');
|
||||
if (!cssnano || !postcss) {
|
||||
return tree;
|
||||
}
|
||||
let promises = [];
|
||||
tree.walk(node => {
|
||||
// Skip SRI, reasons are documented in "minifyJs" module
|
||||
if (node.attrs && 'integrity' in node.attrs) {
|
||||
return node;
|
||||
}
|
||||
if ((0, _helpers.isStyleNode)(node)) {
|
||||
promises.push(processStyleNode(node, cssnanoOptions, cssnano, postcss));
|
||||
} else if (node.attrs && node.attrs.style) {
|
||||
promises.push(processStyleAttr(node, cssnanoOptions, cssnano, postcss));
|
||||
}
|
||||
return node;
|
||||
});
|
||||
return Promise.all(promises).then(() => tree);
|
||||
}
|
||||
function processStyleNode(styleNode, cssnanoOptions, cssnano, postcss) {
|
||||
let css = (0, _helpers.extractCssFromStyleNode)(styleNode);
|
||||
|
||||
// Improve performance by avoiding calling stripCdata again and again
|
||||
let isCdataWrapped = false;
|
||||
if (css.includes('CDATA')) {
|
||||
const strippedCss = stripCdata(css);
|
||||
isCdataWrapped = css !== strippedCss;
|
||||
css = strippedCss;
|
||||
}
|
||||
return postcss([cssnano(cssnanoOptions)]).process(css, postcssOptions).then(result => {
|
||||
if (isCdataWrapped) {
|
||||
return styleNode.content = ['<![CDATA[' + result + ']]>'];
|
||||
}
|
||||
return styleNode.content = [result.css];
|
||||
});
|
||||
}
|
||||
function processStyleAttr(node, cssnanoOptions, cssnano, postcss) {
|
||||
// CSS "color: red;" is invalid. Therefore it should be wrapped inside some selector:
|
||||
// a{color: red;}
|
||||
const wrapperStart = 'a{';
|
||||
const wrapperEnd = '}';
|
||||
const wrappedStyle = wrapperStart + (node.attrs.style || '') + wrapperEnd;
|
||||
return postcss([cssnano(cssnanoOptions)]).process(wrappedStyle, postcssOptions).then(result => {
|
||||
const minifiedCss = result.css;
|
||||
// Remove wrapperStart at the start and wrapperEnd at the end of minifiedCss
|
||||
node.attrs.style = minifiedCss.substring(wrapperStart.length, minifiedCss.length - wrapperEnd.length);
|
||||
});
|
||||
}
|
||||
function stripCdata(css) {
|
||||
const leftStrippedCss = css.replace('<![CDATA[', '');
|
||||
if (leftStrippedCss === css) {
|
||||
return css;
|
||||
}
|
||||
const strippedCss = leftStrippedCss.replace(']]>', '');
|
||||
return leftStrippedCss === strippedCss ? css : strippedCss;
|
||||
}
|
||||
88
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyCss.mjs
generated
vendored
Normal file
88
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyCss.mjs
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
import { isStyleNode, extractCssFromStyleNode, optionalImport } from '../helpers.mjs';
|
||||
|
||||
const postcssOptions = {
|
||||
// Prevent the following warning from being shown:
|
||||
// > Without `from` option PostCSS could generate wrong source map and will not find Browserslist config.
|
||||
// > Set it to CSS file path or to `undefined` to prevent this warning.
|
||||
from: undefined,
|
||||
};
|
||||
|
||||
/** Minify CSS with cssnano */
|
||||
export default async function minifyCss(tree, options, cssnanoOptions) {
|
||||
const cssnano = await optionalImport('cssnano');
|
||||
const postcss = await optionalImport('postcss');
|
||||
|
||||
if (!cssnano || !postcss) {
|
||||
return tree;
|
||||
}
|
||||
|
||||
let promises = [];
|
||||
tree.walk(node => {
|
||||
// Skip SRI, reasons are documented in "minifyJs" module
|
||||
if (node.attrs && 'integrity' in node.attrs) {
|
||||
return node;
|
||||
}
|
||||
|
||||
if (isStyleNode(node)) {
|
||||
promises.push(processStyleNode(node, cssnanoOptions, cssnano, postcss));
|
||||
} else if (node.attrs && node.attrs.style) {
|
||||
promises.push(processStyleAttr(node, cssnanoOptions, cssnano, postcss));
|
||||
}
|
||||
|
||||
return node;
|
||||
});
|
||||
|
||||
return Promise.all(promises).then(() => tree);
|
||||
}
|
||||
|
||||
|
||||
function processStyleNode(styleNode, cssnanoOptions, cssnano, postcss) {
|
||||
let css = extractCssFromStyleNode(styleNode);
|
||||
|
||||
// Improve performance by avoiding calling stripCdata again and again
|
||||
let isCdataWrapped = false;
|
||||
if (css.includes('CDATA')) {
|
||||
const strippedCss = stripCdata(css);
|
||||
isCdataWrapped = css !== strippedCss;
|
||||
css = strippedCss;
|
||||
}
|
||||
|
||||
return postcss([cssnano(cssnanoOptions)])
|
||||
.process(css, postcssOptions)
|
||||
.then(result => {
|
||||
if (isCdataWrapped) {
|
||||
return styleNode.content = ['<![CDATA[' + result + ']]>'];
|
||||
}
|
||||
return styleNode.content = [result.css];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function processStyleAttr(node, cssnanoOptions, cssnano, postcss) {
|
||||
// CSS "color: red;" is invalid. Therefore it should be wrapped inside some selector:
|
||||
// a{color: red;}
|
||||
const wrapperStart = 'a{';
|
||||
const wrapperEnd = '}';
|
||||
const wrappedStyle = wrapperStart + (node.attrs.style || '') + wrapperEnd;
|
||||
|
||||
return postcss([cssnano(cssnanoOptions)])
|
||||
.process(wrappedStyle, postcssOptions)
|
||||
.then(result => {
|
||||
const minifiedCss = result.css;
|
||||
// Remove wrapperStart at the start and wrapperEnd at the end of minifiedCss
|
||||
node.attrs.style = minifiedCss.substring(
|
||||
wrapperStart.length,
|
||||
minifiedCss.length - wrapperEnd.length
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function stripCdata(css) {
|
||||
const leftStrippedCss = css.replace('<![CDATA[', '');
|
||||
if (leftStrippedCss === css) {
|
||||
return css;
|
||||
}
|
||||
|
||||
const strippedCss = leftStrippedCss.replace(']]>', '');
|
||||
return leftStrippedCss === strippedCss ? css : strippedCss;
|
||||
}
|
||||
103
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyJs.cjs
generated
vendored
Normal file
103
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyJs.cjs
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = minifyJs;
|
||||
var _helpers = require("../helpers.cjs");
|
||||
var _removeRedundantAttributes = require("./removeRedundantAttributes.cjs");
|
||||
/** Minify JS with Terser */
|
||||
async function minifyJs(tree, options, terserOptions) {
|
||||
const terser = await (0, _helpers.optionalImport)('terser');
|
||||
if (!terser) return tree;
|
||||
let promises = [];
|
||||
tree.walk(node => {
|
||||
const nodeAttrs = node.attrs || {};
|
||||
|
||||
/**
|
||||
* Skip SRI
|
||||
*
|
||||
* If the input <script /> has an SRI attribute, it means that the original <script /> could be trusted,
|
||||
* and should not be altered anymore.
|
||||
*
|
||||
* htmlnano is exactly an MITM that SRI is designed to protect from. If htmlnano or its dependencies get
|
||||
* compromised and introduces malicious code, then it is up to the original SRI to protect the end user.
|
||||
*
|
||||
* So htmlnano will simply skip <script /> that has SRI.
|
||||
* If developers do trust htmlnano, they should generate SRI after htmlnano modify the <script />.
|
||||
*/
|
||||
if ('integrity' in nodeAttrs) {
|
||||
return node;
|
||||
}
|
||||
if (node.tag && node.tag === 'script') {
|
||||
const mimeType = nodeAttrs.type || 'text/javascript';
|
||||
if (_removeRedundantAttributes.redundantScriptTypes.has(mimeType) || mimeType === 'module') {
|
||||
promises.push(processScriptNode(node, terserOptions, terser));
|
||||
}
|
||||
}
|
||||
if (node.attrs) {
|
||||
promises = promises.concat(processNodeWithOnAttrs(node, terserOptions, terser));
|
||||
}
|
||||
return node;
|
||||
});
|
||||
return Promise.all(promises).then(() => tree);
|
||||
}
|
||||
function stripCdata(js) {
|
||||
const leftStrippedJs = js.replace(/\/\/\s*<!\[CDATA\[/, '').replace(/\/\*\s*<!\[CDATA\[\s*\*\//, '');
|
||||
if (leftStrippedJs === js) {
|
||||
return js;
|
||||
}
|
||||
const strippedJs = leftStrippedJs.replace(/\/\/\s*\]\]>/, '').replace(/\/\*\s*\]\]>\s*\*\//, '');
|
||||
return leftStrippedJs === strippedJs ? js : strippedJs;
|
||||
}
|
||||
function processScriptNode(scriptNode, terserOptions, terser) {
|
||||
let js = (scriptNode.content || []).join('').trim();
|
||||
if (!js) {
|
||||
return scriptNode;
|
||||
}
|
||||
|
||||
// Improve performance by avoiding calling stripCdata again and again
|
||||
let isCdataWrapped = false;
|
||||
if (js.includes('CDATA')) {
|
||||
const strippedJs = stripCdata(js);
|
||||
isCdataWrapped = js !== strippedJs;
|
||||
js = strippedJs;
|
||||
}
|
||||
return terser.minify(js, terserOptions).then(result => {
|
||||
if (result.error) {
|
||||
throw new Error(result.error);
|
||||
}
|
||||
if (result.code === undefined) {
|
||||
return;
|
||||
}
|
||||
let content = result.code;
|
||||
if (isCdataWrapped) {
|
||||
content = '/*<![CDATA[*/' + content + '/*]]>*/';
|
||||
}
|
||||
scriptNode.content = [content];
|
||||
});
|
||||
}
|
||||
function processNodeWithOnAttrs(node, terserOptions, terser) {
|
||||
const jsWrapperStart = 'a=function(){';
|
||||
const jsWrapperEnd = '};a();';
|
||||
const promises = [];
|
||||
for (const attrName of Object.keys(node.attrs || {})) {
|
||||
if (!(0, _helpers.isEventHandler)(attrName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// For example onclick="return false" is valid,
|
||||
// but "return false;" is invalid (error: 'return' outside of function)
|
||||
// Therefore the attribute's code should be wrapped inside function:
|
||||
// "function _(){return false;}"
|
||||
let wrappedJs = jsWrapperStart + node.attrs[attrName] + jsWrapperEnd;
|
||||
let promise = terser.minify(wrappedJs, terserOptions).then(({
|
||||
code
|
||||
}) => {
|
||||
let minifiedJs = code.substring(jsWrapperStart.length, code.length - jsWrapperEnd.length);
|
||||
node.attrs[attrName] = minifiedJs;
|
||||
});
|
||||
promises.push(promise);
|
||||
}
|
||||
return promises;
|
||||
}
|
||||
121
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyJs.mjs
generated
vendored
Normal file
121
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyJs.mjs
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
import { isEventHandler, optionalImport } from '../helpers.mjs';
|
||||
import { redundantScriptTypes } from './removeRedundantAttributes.mjs';
|
||||
|
||||
/** Minify JS with Terser */
|
||||
export default async function minifyJs (tree, options, terserOptions) {
|
||||
const terser = await optionalImport('terser');
|
||||
|
||||
if (!terser) return tree;
|
||||
|
||||
let promises = [];
|
||||
tree.walk(node => {
|
||||
const nodeAttrs = node.attrs || {};
|
||||
|
||||
/**
|
||||
* Skip SRI
|
||||
*
|
||||
* If the input <script /> has an SRI attribute, it means that the original <script /> could be trusted,
|
||||
* and should not be altered anymore.
|
||||
*
|
||||
* htmlnano is exactly an MITM that SRI is designed to protect from. If htmlnano or its dependencies get
|
||||
* compromised and introduces malicious code, then it is up to the original SRI to protect the end user.
|
||||
*
|
||||
* So htmlnano will simply skip <script /> that has SRI.
|
||||
* If developers do trust htmlnano, they should generate SRI after htmlnano modify the <script />.
|
||||
*/
|
||||
if ('integrity' in nodeAttrs) {
|
||||
return node;
|
||||
}
|
||||
|
||||
if (node.tag && node.tag === 'script') {
|
||||
const mimeType = nodeAttrs.type || 'text/javascript';
|
||||
if (redundantScriptTypes.has(mimeType) || mimeType === 'module') {
|
||||
promises.push(processScriptNode(node, terserOptions, terser));
|
||||
}
|
||||
}
|
||||
|
||||
if (node.attrs) {
|
||||
promises = promises.concat(processNodeWithOnAttrs(node, terserOptions, terser));
|
||||
}
|
||||
|
||||
return node;
|
||||
});
|
||||
|
||||
return Promise.all(promises).then(() => tree);
|
||||
}
|
||||
|
||||
|
||||
function stripCdata (js) {
|
||||
const leftStrippedJs = js.replace(/\/\/\s*<!\[CDATA\[/, '').replace(/\/\*\s*<!\[CDATA\[\s*\*\//, '');
|
||||
if (leftStrippedJs === js) {
|
||||
return js;
|
||||
}
|
||||
|
||||
const strippedJs = leftStrippedJs.replace(/\/\/\s*\]\]>/, '').replace(/\/\*\s*\]\]>\s*\*\//, '');
|
||||
return leftStrippedJs === strippedJs ? js : strippedJs;
|
||||
}
|
||||
|
||||
|
||||
function processScriptNode (scriptNode, terserOptions, terser) {
|
||||
let js = (scriptNode.content || []).join('').trim();
|
||||
if (!js) {
|
||||
return scriptNode;
|
||||
}
|
||||
|
||||
// Improve performance by avoiding calling stripCdata again and again
|
||||
let isCdataWrapped = false;
|
||||
if (js.includes('CDATA')) {
|
||||
const strippedJs = stripCdata(js);
|
||||
isCdataWrapped = js !== strippedJs;
|
||||
js = strippedJs;
|
||||
}
|
||||
|
||||
return terser
|
||||
.minify(js, terserOptions)
|
||||
.then(result => {
|
||||
if (result.error) {
|
||||
throw new Error(result.error);
|
||||
}
|
||||
if (result.code === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
let content = result.code;
|
||||
if (isCdataWrapped) {
|
||||
content = '/*<![CDATA[*/' + content + '/*]]>*/';
|
||||
}
|
||||
|
||||
scriptNode.content = [content];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function processNodeWithOnAttrs (node, terserOptions, terser) {
|
||||
const jsWrapperStart = 'a=function(){';
|
||||
const jsWrapperEnd = '};a();';
|
||||
|
||||
const promises = [];
|
||||
for (const attrName of Object.keys(node.attrs || {})) {
|
||||
if (!isEventHandler(attrName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// For example onclick="return false" is valid,
|
||||
// but "return false;" is invalid (error: 'return' outside of function)
|
||||
// Therefore the attribute's code should be wrapped inside function:
|
||||
// "function _(){return false;}"
|
||||
let wrappedJs = jsWrapperStart + node.attrs[attrName] + jsWrapperEnd;
|
||||
let promise = terser
|
||||
.minify(wrappedJs, terserOptions)
|
||||
.then(({ code }) => {
|
||||
let minifiedJs = code.substring(
|
||||
jsWrapperStart.length,
|
||||
code.length - jsWrapperEnd.length
|
||||
);
|
||||
node.attrs[attrName] = minifiedJs;
|
||||
});
|
||||
promises.push(promise);
|
||||
}
|
||||
|
||||
return promises;
|
||||
}
|
||||
24
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyJson.cjs
generated
vendored
Normal file
24
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyJson.cjs
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.onContent = onContent;
|
||||
const rNodeAttrsTypeJson = /(\/|\+)json/;
|
||||
function onContent() {
|
||||
return (content, node) => {
|
||||
// Skip SRI, reasons are documented in "minifyJs" module
|
||||
if (node.attrs && 'integrity' in node.attrs) {
|
||||
return content;
|
||||
}
|
||||
if (node.attrs && node.attrs.type && rNodeAttrsTypeJson.test(node.attrs.type)) {
|
||||
try {
|
||||
// cast minified JSON to an array
|
||||
return [JSON.stringify(JSON.parse((content || []).join('')))];
|
||||
} catch (error) {
|
||||
// Invalid JSON
|
||||
}
|
||||
}
|
||||
return content;
|
||||
};
|
||||
}
|
||||
21
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyJson.mjs
generated
vendored
Normal file
21
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyJson.mjs
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
const rNodeAttrsTypeJson = /(\/|\+)json/;
|
||||
|
||||
export function onContent() {
|
||||
return (content, node) => {
|
||||
// Skip SRI, reasons are documented in "minifyJs" module
|
||||
if (node.attrs && 'integrity' in node.attrs) {
|
||||
return content;
|
||||
}
|
||||
|
||||
if (node.attrs && node.attrs.type && rNodeAttrsTypeJson.test(node.attrs.type)) {
|
||||
try {
|
||||
// cast minified JSON to an array
|
||||
return [JSON.stringify(JSON.parse((content || []).join('')))];
|
||||
} catch (error) {
|
||||
// Invalid JSON
|
||||
}
|
||||
}
|
||||
|
||||
return content;
|
||||
};
|
||||
}
|
||||
37
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifySvg.cjs
generated
vendored
Normal file
37
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifySvg.cjs
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = minifySvg;
|
||||
var _helpers = require("../helpers.cjs");
|
||||
/** Minify SVG with SVGO */
|
||||
async function minifySvg(tree, options, svgoOptions = {}) {
|
||||
const svgo = await (0, _helpers.optionalImport)('svgo');
|
||||
if (!svgo) return tree;
|
||||
tree.match({
|
||||
tag: 'svg'
|
||||
}, node => {
|
||||
let svgStr = tree.render(node, {
|
||||
closingSingleTag: 'slash',
|
||||
quoteAllAttributes: true
|
||||
});
|
||||
try {
|
||||
const result = svgo.optimize(svgStr, svgoOptions);
|
||||
node.tag = false;
|
||||
node.attrs = {};
|
||||
// result.data is a string, we need to cast it to an array
|
||||
node.content = [result.data];
|
||||
return node;
|
||||
} catch (error) {
|
||||
console.error('htmlnano fails to minify the svg:');
|
||||
console.error(error);
|
||||
if (error.name === 'SvgoParserError') {
|
||||
console.error(error.toString());
|
||||
}
|
||||
// We return the node as-is
|
||||
return node;
|
||||
}
|
||||
});
|
||||
return tree;
|
||||
}
|
||||
30
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifySvg.mjs
generated
vendored
Normal file
30
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifySvg.mjs
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
import { optionalImport } from '../helpers.mjs';
|
||||
|
||||
/** Minify SVG with SVGO */
|
||||
export default async function minifySvg(tree, options, svgoOptions = {}) {
|
||||
const svgo = await optionalImport('svgo');
|
||||
|
||||
if (!svgo) return tree;
|
||||
|
||||
tree.match({tag: 'svg'}, node => {
|
||||
let svgStr = tree.render(node, { closingSingleTag: 'slash', quoteAllAttributes: true });
|
||||
try {
|
||||
const result = svgo.optimize(svgStr, svgoOptions);
|
||||
node.tag = false;
|
||||
node.attrs = {};
|
||||
// result.data is a string, we need to cast it to an array
|
||||
node.content = [result.data];
|
||||
return node;
|
||||
} catch (error) {
|
||||
console.error('htmlnano fails to minify the svg:');
|
||||
console.error(error);
|
||||
if (error.name === 'SvgoParserError') {
|
||||
console.error(error.toString());
|
||||
}
|
||||
// We return the node as-is
|
||||
return node;
|
||||
}
|
||||
});
|
||||
|
||||
return tree;
|
||||
}
|
||||
141
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyUrls.cjs
generated
vendored
Normal file
141
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyUrls.cjs
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = minifyUrls;
|
||||
var _helpers = require("../helpers.cjs");
|
||||
// Adopts from https://github.com/kangax/html-minifier/blob/51ce10f4daedb1de483ffbcccecc41be1c873da2/src/htmlminifier.js#L209-L221
|
||||
const tagsHaveUriValuesForAttributes = new Set(['a', 'area', 'link', 'base', 'object', 'blockquote', 'q', 'del', 'ins', 'form', 'input', 'head', 'audio', 'embed', 'iframe', 'img', 'script', 'track', 'video']);
|
||||
const tagsHasHrefAttributes = new Set(['a', 'area', 'link', 'base']);
|
||||
const attributesOfImgTagHasUriValues = new Set(['src', 'longdesc', 'usemap']);
|
||||
const attributesOfObjectTagHasUriValues = new Set(['classid', 'codebase', 'data', 'usemap']);
|
||||
const tagsHasCiteAttributes = new Set(['blockquote', 'q', 'ins', 'del']);
|
||||
const tagsHasSrcAttributes = new Set(['audio', 'embed', 'iframe', 'img', 'input', 'script', 'track', 'video',
|
||||
/**
|
||||
* https://html.spec.whatwg.org/#attr-source-src
|
||||
*
|
||||
* Although most of browsers recommend not to use "src" in <source>,
|
||||
* but technically it does comply with HTML Standard.
|
||||
*/
|
||||
'source']);
|
||||
const isUriTypeAttribute = (tag, attr) => {
|
||||
return tagsHasHrefAttributes.has(tag) && attr === 'href' || tag === 'img' && attributesOfImgTagHasUriValues.has(attr) || tag === 'object' && attributesOfObjectTagHasUriValues.has(attr) || tagsHasCiteAttributes.has(tag) && attr === 'cite' || tag === 'form' && attr === 'action' || tag === 'input' && attr === 'usemap' || tag === 'head' && attr === 'profile' || tag === 'script' && attr === 'for' || tagsHasSrcAttributes.has(tag) && attr === 'src';
|
||||
};
|
||||
const isSrcsetAttribute = (tag, attr) => {
|
||||
return tag === 'source' && attr === 'srcset' || tag === 'img' && attr === 'srcset' || tag === 'link' && attr === 'imagesrcset';
|
||||
};
|
||||
const processModuleOptions = options => {
|
||||
// FIXME!
|
||||
// relateurl@1.0.0-alpha only supports URL while stable version (0.2.7) only supports string
|
||||
// should convert input into URL instance after relateurl@1 is stable
|
||||
if (typeof options === 'string') return options;
|
||||
if (options instanceof URL) return options.toString();
|
||||
return false;
|
||||
};
|
||||
const isLinkRelCanonical = ({
|
||||
tag,
|
||||
attrs
|
||||
}) => {
|
||||
// Return false early for non-"link" tag
|
||||
if (tag !== 'link') return false;
|
||||
for (const [attrName, attrValue] of Object.entries(attrs)) {
|
||||
if (attrName.toLowerCase() === 'rel' && attrValue === 'canonical') return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const JAVASCRIPT_URL_PROTOCOL = 'javascript:';
|
||||
let relateUrlInstance;
|
||||
let STORED_URL_BASE;
|
||||
|
||||
/** Convert absolute url into relative url */
|
||||
async function minifyUrls(tree, options, moduleOptions) {
|
||||
const RelateUrl = await (0, _helpers.optionalImport)('relateurl');
|
||||
const srcset = await (0, _helpers.optionalImport)('srcset');
|
||||
const terser = await (0, _helpers.optionalImport)('terser');
|
||||
let promises = [];
|
||||
const urlBase = processModuleOptions(moduleOptions);
|
||||
|
||||
// Invalid configuration, return tree directly
|
||||
if (!urlBase) return tree;
|
||||
|
||||
/** Bring up a reusable RelateUrl instances (only once)
|
||||
*
|
||||
* STORED_URL_BASE is used to invalidate RelateUrl instances,
|
||||
* avoiding require.cache acrossing multiple htmlnano instance with different configuration,
|
||||
* e.g. unit tests cases.
|
||||
*/
|
||||
if (!relateUrlInstance || STORED_URL_BASE !== urlBase) {
|
||||
if (RelateUrl) {
|
||||
relateUrlInstance = new RelateUrl(urlBase);
|
||||
}
|
||||
STORED_URL_BASE = urlBase;
|
||||
}
|
||||
tree.walk(node => {
|
||||
if (!node.attrs) return node;
|
||||
if (!node.tag) return node;
|
||||
if (!tagsHaveUriValuesForAttributes.has(node.tag)) return node;
|
||||
|
||||
// Prevent link[rel=canonical] being processed
|
||||
// Can't be excluded by isUriTypeAttribute()
|
||||
if (isLinkRelCanonical(node)) return node;
|
||||
for (const [attrName, attrValue] of Object.entries(node.attrs)) {
|
||||
const attrNameLower = attrName.toLowerCase();
|
||||
if (isUriTypeAttribute(node.tag, attrNameLower)) {
|
||||
if (isJavaScriptUrl(attrValue)) {
|
||||
promises.push(minifyJavaScriptUrl(node, attrName, terser));
|
||||
} else {
|
||||
if (relateUrlInstance) {
|
||||
// FIXME!
|
||||
// relateurl@1.0.0-alpha only supports URL while stable version (0.2.7) only supports string
|
||||
// the WHATWG URL API is very strict while attrValue might not be a valid URL
|
||||
// new URL should be used, and relateUrl#relate should be wrapped in try...catch after relateurl@1 is stable
|
||||
node.attrs[attrName] = relateUrlInstance.relate(attrValue);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (isSrcsetAttribute(node.tag, attrNameLower)) {
|
||||
if (srcset) {
|
||||
try {
|
||||
const parsedSrcset = srcset.parse(attrValue, {
|
||||
strict: true
|
||||
});
|
||||
node.attrs[attrName] = srcset.stringify(parsedSrcset.map(srcset => {
|
||||
if (relateUrlInstance) {
|
||||
srcset.url = relateUrlInstance.relate(srcset.url);
|
||||
}
|
||||
return srcset;
|
||||
}));
|
||||
} catch (e) {
|
||||
// srcset will throw an Error for invalid srcset.
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return node;
|
||||
});
|
||||
if (promises.length > 0) return Promise.all(promises).then(() => tree);
|
||||
return Promise.resolve(tree);
|
||||
}
|
||||
function isJavaScriptUrl(url) {
|
||||
return typeof url === 'string' && url.toLowerCase().startsWith(JAVASCRIPT_URL_PROTOCOL);
|
||||
}
|
||||
const jsWrapperStart = 'function a(){';
|
||||
const jsWrapperEnd = '}a();';
|
||||
function minifyJavaScriptUrl(node, attrName, terser) {
|
||||
if (!terser) return Promise.resolve();
|
||||
let result = node.attrs[attrName];
|
||||
if (result) {
|
||||
result = jsWrapperStart + result.slice(JAVASCRIPT_URL_PROTOCOL.length) + jsWrapperEnd;
|
||||
return terser.minify(result, {}) // Default Option is good enough
|
||||
.then(({
|
||||
code
|
||||
}) => {
|
||||
const minifiedJs = code.substring(jsWrapperStart.length, code.length - jsWrapperEnd.length);
|
||||
node.attrs[attrName] = JAVASCRIPT_URL_PROTOCOL + minifiedJs;
|
||||
});
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
229
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyUrls.mjs
generated
vendored
Normal file
229
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/minifyUrls.mjs
generated
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
import { optionalImport } from '../helpers.mjs';
|
||||
|
||||
// Adopts from https://github.com/kangax/html-minifier/blob/51ce10f4daedb1de483ffbcccecc41be1c873da2/src/htmlminifier.js#L209-L221
|
||||
const tagsHaveUriValuesForAttributes = new Set([
|
||||
'a',
|
||||
'area',
|
||||
'link',
|
||||
'base',
|
||||
'object',
|
||||
'blockquote',
|
||||
'q',
|
||||
'del',
|
||||
'ins',
|
||||
'form',
|
||||
'input',
|
||||
'head',
|
||||
'audio',
|
||||
'embed',
|
||||
'iframe',
|
||||
'img',
|
||||
'script',
|
||||
'track',
|
||||
'video',
|
||||
]);
|
||||
|
||||
const tagsHasHrefAttributes = new Set([
|
||||
'a',
|
||||
'area',
|
||||
'link',
|
||||
'base'
|
||||
]);
|
||||
|
||||
const attributesOfImgTagHasUriValues = new Set([
|
||||
'src',
|
||||
'longdesc',
|
||||
'usemap'
|
||||
]);
|
||||
|
||||
const attributesOfObjectTagHasUriValues = new Set([
|
||||
'classid',
|
||||
'codebase',
|
||||
'data',
|
||||
'usemap'
|
||||
]);
|
||||
|
||||
const tagsHasCiteAttributes = new Set([
|
||||
'blockquote',
|
||||
'q',
|
||||
'ins',
|
||||
'del'
|
||||
]);
|
||||
|
||||
const tagsHasSrcAttributes = new Set([
|
||||
'audio',
|
||||
'embed',
|
||||
'iframe',
|
||||
'img',
|
||||
'input',
|
||||
'script',
|
||||
'track',
|
||||
'video',
|
||||
/**
|
||||
* https://html.spec.whatwg.org/#attr-source-src
|
||||
*
|
||||
* Although most of browsers recommend not to use "src" in <source>,
|
||||
* but technically it does comply with HTML Standard.
|
||||
*/
|
||||
'source'
|
||||
]);
|
||||
|
||||
const isUriTypeAttribute = (tag, attr) => {
|
||||
return (
|
||||
tagsHasHrefAttributes.has(tag) && attr === 'href' ||
|
||||
tag === 'img' && attributesOfImgTagHasUriValues.has(attr) ||
|
||||
tag === 'object' && attributesOfObjectTagHasUriValues.has(attr) ||
|
||||
tagsHasCiteAttributes.has(tag) && attr === 'cite' ||
|
||||
tag === 'form' && attr === 'action' ||
|
||||
tag === 'input' && attr === 'usemap' ||
|
||||
tag === 'head' && attr === 'profile' ||
|
||||
tag === 'script' && attr === 'for' ||
|
||||
tagsHasSrcAttributes.has(tag) && attr === 'src'
|
||||
);
|
||||
};
|
||||
|
||||
const isSrcsetAttribute = (tag, attr) => {
|
||||
return (
|
||||
tag === 'source' && attr === 'srcset' ||
|
||||
tag === 'img' && attr === 'srcset' ||
|
||||
tag === 'link' && attr === 'imagesrcset'
|
||||
);
|
||||
};
|
||||
|
||||
const processModuleOptions = options => {
|
||||
// FIXME!
|
||||
// relateurl@1.0.0-alpha only supports URL while stable version (0.2.7) only supports string
|
||||
// should convert input into URL instance after relateurl@1 is stable
|
||||
if (typeof options === 'string') return options;
|
||||
if (options instanceof URL) return options.toString();
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const isLinkRelCanonical = ({ tag, attrs }) => {
|
||||
// Return false early for non-"link" tag
|
||||
if (tag !== 'link') return false;
|
||||
|
||||
for (const [attrName, attrValue] of Object.entries(attrs)) {
|
||||
if (attrName.toLowerCase() === 'rel' && attrValue === 'canonical') return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const JAVASCRIPT_URL_PROTOCOL = 'javascript:';
|
||||
|
||||
let relateUrlInstance;
|
||||
let STORED_URL_BASE;
|
||||
|
||||
/** Convert absolute url into relative url */
|
||||
export default async function minifyUrls(tree, options, moduleOptions) {
|
||||
const RelateUrl = await optionalImport('relateurl');
|
||||
const srcset = await optionalImport('srcset');
|
||||
const terser = await optionalImport('terser');
|
||||
|
||||
let promises = [];
|
||||
|
||||
const urlBase = processModuleOptions(moduleOptions);
|
||||
|
||||
// Invalid configuration, return tree directly
|
||||
if (!urlBase) return tree;
|
||||
|
||||
/** Bring up a reusable RelateUrl instances (only once)
|
||||
*
|
||||
* STORED_URL_BASE is used to invalidate RelateUrl instances,
|
||||
* avoiding require.cache acrossing multiple htmlnano instance with different configuration,
|
||||
* e.g. unit tests cases.
|
||||
*/
|
||||
if (!relateUrlInstance || STORED_URL_BASE !== urlBase) {
|
||||
if (RelateUrl) {
|
||||
relateUrlInstance = new RelateUrl(urlBase);
|
||||
}
|
||||
STORED_URL_BASE = urlBase;
|
||||
}
|
||||
|
||||
tree.walk(node => {
|
||||
if (!node.attrs) return node;
|
||||
|
||||
if (!node.tag) return node;
|
||||
|
||||
if (!tagsHaveUriValuesForAttributes.has(node.tag)) return node;
|
||||
|
||||
// Prevent link[rel=canonical] being processed
|
||||
// Can't be excluded by isUriTypeAttribute()
|
||||
if (isLinkRelCanonical(node)) return node;
|
||||
|
||||
for (const [attrName, attrValue] of Object.entries(node.attrs)) {
|
||||
const attrNameLower = attrName.toLowerCase();
|
||||
|
||||
if (isUriTypeAttribute(node.tag, attrNameLower)) {
|
||||
if (isJavaScriptUrl(attrValue)) {
|
||||
promises.push(minifyJavaScriptUrl(node, attrName, terser));
|
||||
} else {
|
||||
if (relateUrlInstance) {
|
||||
// FIXME!
|
||||
// relateurl@1.0.0-alpha only supports URL while stable version (0.2.7) only supports string
|
||||
// the WHATWG URL API is very strict while attrValue might not be a valid URL
|
||||
// new URL should be used, and relateUrl#relate should be wrapped in try...catch after relateurl@1 is stable
|
||||
node.attrs[attrName] = relateUrlInstance.relate(attrValue);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isSrcsetAttribute(node.tag, attrNameLower)) {
|
||||
if (srcset) {
|
||||
try {
|
||||
const parsedSrcset = srcset.parse(attrValue, { strict: true });
|
||||
|
||||
node.attrs[attrName] = srcset.stringify(parsedSrcset.map(srcset => {
|
||||
if (relateUrlInstance) {
|
||||
srcset.url = relateUrlInstance.relate(srcset.url);
|
||||
}
|
||||
|
||||
return srcset;
|
||||
}));
|
||||
} catch (e) {
|
||||
// srcset will throw an Error for invalid srcset.
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
});
|
||||
|
||||
if (promises.length > 0) return Promise.all(promises).then(() => tree);
|
||||
return Promise.resolve(tree);
|
||||
}
|
||||
|
||||
function isJavaScriptUrl(url) {
|
||||
return typeof url === 'string' && url.toLowerCase().startsWith(JAVASCRIPT_URL_PROTOCOL);
|
||||
}
|
||||
|
||||
const jsWrapperStart = 'function a(){';
|
||||
const jsWrapperEnd = '}a();';
|
||||
|
||||
function minifyJavaScriptUrl(node, attrName, terser) {
|
||||
if (!terser) return Promise.resolve();
|
||||
|
||||
let result = node.attrs[attrName];
|
||||
if (result) {
|
||||
result = jsWrapperStart + result.slice(JAVASCRIPT_URL_PROTOCOL.length) + jsWrapperEnd;
|
||||
|
||||
return terser
|
||||
.minify(result, {}) // Default Option is good enough
|
||||
.then(({ code }) => {
|
||||
const minifiedJs = code.substring(
|
||||
jsWrapperStart.length,
|
||||
code.length - jsWrapperEnd.length
|
||||
);
|
||||
node.attrs[attrName] = JAVASCRIPT_URL_PROTOCOL + minifiedJs;
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
120
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/normalizeAttributeValues.cjs
generated
vendored
Normal file
120
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/normalizeAttributeValues.cjs
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.onAttrs = onAttrs;
|
||||
const caseInsensitiveAttributes = {
|
||||
autocomplete: ['form'],
|
||||
charset: ['meta', 'script'],
|
||||
contenteditable: null,
|
||||
crossorigin: ['audio', 'img', 'link', 'script', 'video'],
|
||||
dir: null,
|
||||
draggable: null,
|
||||
dropzone: null,
|
||||
formmethod: ['button', 'input'],
|
||||
inputmode: ['input', 'textarea'],
|
||||
kind: ['track'],
|
||||
method: ['form'],
|
||||
preload: ['audio', 'video'],
|
||||
referrerpolicy: null,
|
||||
sandbox: ['iframe'],
|
||||
spellcheck: null,
|
||||
scope: ['th'],
|
||||
shape: ['area'],
|
||||
sizes: ['link'],
|
||||
step: ['input'],
|
||||
translate: null,
|
||||
type: ['a', 'link', 'button', 'embed', 'object', 'script', 'source', 'style', 'input', 'menu', 'menuitem'],
|
||||
wrap: ['textarea']
|
||||
};
|
||||
|
||||
// https://html.spec.whatwg.org/#invalid-value-default
|
||||
/** @typedef { [key: string]: { tag: null | string[], default: string, valid: string[] } } */
|
||||
const invalidValueDefault = {
|
||||
crossorigin: {
|
||||
tag: null,
|
||||
default: 'anonymous',
|
||||
valid: ['', 'anonymous', 'use-credentials']
|
||||
},
|
||||
// https://html.spec.whatwg.org/#referrer-policy-attributes
|
||||
// The attribute's invalid value default and missing value default are both the empty string state.
|
||||
referrerpolicy: {
|
||||
tag: null,
|
||||
default: '',
|
||||
valid: ['', 'url', 'origin', 'no-referrer', 'no-referrer-when-downgrade', 'same-origin', 'origin-when-cross-origin', 'strict-origin-when-cross-origin', 'unsafe-url']
|
||||
},
|
||||
// https://html.spec.whatwg.org/#lazy-loading-attributes
|
||||
loading: {
|
||||
tag: ['img', 'iframe'],
|
||||
default: 'eager',
|
||||
valid: ['lazy', 'eager']
|
||||
},
|
||||
// https://html.spec.whatwg.org/#the-img-element
|
||||
// https://html.spec.whatwg.org/#image-decoding-hint
|
||||
decoding: {
|
||||
tag: ['img'],
|
||||
default: 'auto',
|
||||
valid: ['auto', 'sync', 'async']
|
||||
},
|
||||
// https://html.spec.whatwg.org/#the-track-element
|
||||
kind: {
|
||||
tag: ['track'],
|
||||
default: 'metadata',
|
||||
valid: ['subtitles', 'captions', 'descriptions', 'chapters', 'metadata']
|
||||
},
|
||||
type: {
|
||||
tag: ['button'],
|
||||
default: 'submit',
|
||||
valid: ['submit', 'reset', 'button']
|
||||
},
|
||||
wrap: {
|
||||
tag: ['textarea'],
|
||||
default: 'soft',
|
||||
valid: ['soft', 'hard']
|
||||
},
|
||||
// https://html.spec.whatwg.org/#the-hidden-attribute
|
||||
hidden: {
|
||||
tag: null,
|
||||
default: 'hidden',
|
||||
valid: ['hidden', 'until-found']
|
||||
},
|
||||
// https://html.spec.whatwg.org/#autocapitalization
|
||||
autocapitalize: {
|
||||
tag: null,
|
||||
default: 'sentences',
|
||||
valid: ['none', 'off', 'on', 'sentences', 'words', 'characters']
|
||||
},
|
||||
// https://html.spec.whatwg.org/#the-marquee-element
|
||||
behavior: {
|
||||
tag: ['marquee'],
|
||||
default: 'scroll',
|
||||
valid: ['scroll', 'slide', 'alternate']
|
||||
},
|
||||
direction: {
|
||||
tag: ['marquee'],
|
||||
default: 'left',
|
||||
valid: ['left', 'right', 'up', 'down']
|
||||
}
|
||||
};
|
||||
function onAttrs() {
|
||||
return (attrs, node) => {
|
||||
const newAttrs = attrs;
|
||||
Object.entries(attrs).forEach(([attrName, attrValue]) => {
|
||||
let newAttrValue = attrValue;
|
||||
if (Object.hasOwnProperty.call(caseInsensitiveAttributes, attrName) && (caseInsensitiveAttributes[attrName] === null || caseInsensitiveAttributes[attrName].includes(node.tag))) {
|
||||
newAttrValue = typeof attrValue.toLowerCase === 'function' ? attrValue.toLowerCase() : attrValue;
|
||||
}
|
||||
if (Object.hasOwnProperty.call(invalidValueDefault, attrName)) {
|
||||
const meta = invalidValueDefault[attrName];
|
||||
if (meta.tag === null || node && node.tag && meta.tag.includes(node.tag)) {
|
||||
if (!meta.valid.includes(newAttrValue)) {
|
||||
newAttrValue = meta.default;
|
||||
}
|
||||
}
|
||||
}
|
||||
newAttrs[attrName] = newAttrValue;
|
||||
});
|
||||
return newAttrs;
|
||||
};
|
||||
}
|
||||
140
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/normalizeAttributeValues.mjs
generated
vendored
Normal file
140
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/normalizeAttributeValues.mjs
generated
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
const caseInsensitiveAttributes = {
|
||||
autocomplete: ['form'],
|
||||
charset: ['meta', 'script'],
|
||||
contenteditable: null,
|
||||
crossorigin: ['audio', 'img', 'link', 'script', 'video'],
|
||||
dir: null,
|
||||
draggable: null,
|
||||
dropzone: null,
|
||||
formmethod: ['button', 'input'],
|
||||
inputmode: ['input', 'textarea'],
|
||||
kind: ['track'],
|
||||
method: ['form'],
|
||||
preload: ['audio', 'video'],
|
||||
referrerpolicy: null,
|
||||
sandbox: ['iframe'],
|
||||
spellcheck: null,
|
||||
scope: ['th'],
|
||||
shape: ['area'],
|
||||
sizes: ['link'],
|
||||
step: ['input'],
|
||||
translate: null,
|
||||
type: [
|
||||
'a',
|
||||
'link',
|
||||
'button',
|
||||
'embed',
|
||||
'object',
|
||||
'script',
|
||||
'source',
|
||||
'style',
|
||||
'input',
|
||||
'menu',
|
||||
'menuitem'
|
||||
],
|
||||
wrap: ['textarea']
|
||||
};
|
||||
|
||||
// https://html.spec.whatwg.org/#invalid-value-default
|
||||
/** @typedef { [key: string]: { tag: null | string[], default: string, valid: string[] } } */
|
||||
const invalidValueDefault = {
|
||||
crossorigin: {
|
||||
tag: null,
|
||||
default: 'anonymous',
|
||||
valid: ['', 'anonymous', 'use-credentials']
|
||||
},
|
||||
// https://html.spec.whatwg.org/#referrer-policy-attributes
|
||||
// The attribute's invalid value default and missing value default are both the empty string state.
|
||||
referrerpolicy: {
|
||||
tag: null,
|
||||
default: '',
|
||||
valid: ['', 'url', 'origin', 'no-referrer', 'no-referrer-when-downgrade', 'same-origin', 'origin-when-cross-origin', 'strict-origin-when-cross-origin', 'unsafe-url']
|
||||
},
|
||||
// https://html.spec.whatwg.org/#lazy-loading-attributes
|
||||
loading: {
|
||||
tag: ['img', 'iframe'],
|
||||
default: 'eager',
|
||||
valid: ['lazy', 'eager']
|
||||
},
|
||||
// https://html.spec.whatwg.org/#the-img-element
|
||||
// https://html.spec.whatwg.org/#image-decoding-hint
|
||||
decoding: {
|
||||
tag: ['img'],
|
||||
default: 'auto',
|
||||
valid: ['auto', 'sync', 'async']
|
||||
},
|
||||
// https://html.spec.whatwg.org/#the-track-element
|
||||
kind: {
|
||||
tag: ['track'],
|
||||
default: 'metadata',
|
||||
valid: ['subtitles', 'captions', 'descriptions', 'chapters', 'metadata']
|
||||
},
|
||||
type: {
|
||||
tag: ['button'],
|
||||
default: 'submit',
|
||||
valid: ['submit', 'reset', 'button']
|
||||
},
|
||||
wrap: {
|
||||
tag: ['textarea'],
|
||||
default: 'soft',
|
||||
valid: ['soft', 'hard']
|
||||
},
|
||||
// https://html.spec.whatwg.org/#the-hidden-attribute
|
||||
hidden: {
|
||||
tag: null,
|
||||
default: 'hidden',
|
||||
valid: ['hidden', 'until-found']
|
||||
},
|
||||
// https://html.spec.whatwg.org/#autocapitalization
|
||||
autocapitalize: {
|
||||
tag: null,
|
||||
default: 'sentences',
|
||||
valid: ['none', 'off', 'on', 'sentences', 'words', 'characters']
|
||||
},
|
||||
// https://html.spec.whatwg.org/#the-marquee-element
|
||||
behavior: {
|
||||
tag: ['marquee'],
|
||||
default: 'scroll',
|
||||
valid: ['scroll', 'slide', 'alternate']
|
||||
},
|
||||
direction: {
|
||||
tag: ['marquee'],
|
||||
default: 'left',
|
||||
valid: ['left', 'right', 'up', 'down']
|
||||
}
|
||||
};
|
||||
|
||||
export function onAttrs() {
|
||||
return (attrs, node) => {
|
||||
const newAttrs = attrs;
|
||||
|
||||
Object.entries(attrs).forEach(([attrName, attrValue]) => {
|
||||
let newAttrValue = attrValue;
|
||||
|
||||
if (
|
||||
Object.hasOwnProperty.call(caseInsensitiveAttributes, attrName)
|
||||
&& (
|
||||
caseInsensitiveAttributes[attrName] === null
|
||||
|| caseInsensitiveAttributes[attrName].includes(node.tag)
|
||||
)
|
||||
) {
|
||||
newAttrValue = typeof attrValue.toLowerCase === 'function' ? attrValue.toLowerCase() : attrValue;
|
||||
}
|
||||
|
||||
if (
|
||||
Object.hasOwnProperty.call(invalidValueDefault, attrName)
|
||||
) {
|
||||
const meta = invalidValueDefault[attrName];
|
||||
if (meta.tag === null || (node && node.tag && meta.tag.includes(node.tag))) {
|
||||
if (!meta.valid.includes(newAttrValue)) {
|
||||
newAttrValue = meta.default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newAttrs[attrName] = newAttrValue;
|
||||
});
|
||||
|
||||
return newAttrs;
|
||||
};
|
||||
}
|
||||
17
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeAttributeQuotes.cjs
generated
vendored
Normal file
17
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeAttributeQuotes.cjs
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = removeAttributeQuotes;
|
||||
// Specification: https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
|
||||
// See also: https://github.com/posthtml/posthtml-render/pull/30
|
||||
// See also: https://github.com/posthtml/htmlnano/issues/6#issuecomment-707105334
|
||||
|
||||
/** Disable quoteAllAttributes while not overriding the configuration */
|
||||
function removeAttributeQuotes(tree) {
|
||||
if (tree.options && typeof tree.options.quoteAllAttributes === 'undefined') {
|
||||
tree.options.quoteAllAttributes = false;
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
12
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeAttributeQuotes.mjs
generated
vendored
Normal file
12
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeAttributeQuotes.mjs
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// Specification: https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
|
||||
// See also: https://github.com/posthtml/posthtml-render/pull/30
|
||||
// See also: https://github.com/posthtml/htmlnano/issues/6#issuecomment-707105334
|
||||
|
||||
/** Disable quoteAllAttributes while not overriding the configuration */
|
||||
export default function removeAttributeQuotes(tree) {
|
||||
if (tree.options && typeof tree.options.quoteAllAttributes === 'undefined') {
|
||||
tree.options.quoteAllAttributes = false;
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
86
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeComments.cjs
generated
vendored
Normal file
86
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeComments.cjs
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.onContent = onContent;
|
||||
exports.onNode = onNode;
|
||||
var _helpers = require("../helpers.cjs");
|
||||
const MATCH_EXCERPT_REGEXP = /<!-- ?more ?-->/i;
|
||||
|
||||
/** Removes HTML comments */
|
||||
function onNode(options, removeType) {
|
||||
if (removeType !== 'all' && removeType !== 'safe' && !isMatcher(removeType)) {
|
||||
removeType = 'safe';
|
||||
}
|
||||
return node => {
|
||||
if (isCommentToRemove(node, removeType)) {
|
||||
return '';
|
||||
}
|
||||
return node;
|
||||
};
|
||||
}
|
||||
function onContent(options, removeType) {
|
||||
if (removeType !== 'all' && removeType !== 'safe' && !isMatcher(removeType)) {
|
||||
removeType = 'safe';
|
||||
}
|
||||
return contents => {
|
||||
return contents.filter(content => !isCommentToRemove(content, removeType));
|
||||
};
|
||||
}
|
||||
function isCommentToRemove(text, removeType) {
|
||||
if (typeof text !== 'string') {
|
||||
return false;
|
||||
}
|
||||
if (!(0, _helpers.isComment)(text)) {
|
||||
// Not HTML comment
|
||||
return false;
|
||||
}
|
||||
if (removeType === 'safe') {
|
||||
const isNoindex = text === '<!--noindex-->' || text === '<!--/noindex-->';
|
||||
// Don't remove noindex comments.
|
||||
// See: https://yandex.com/support/webmaster/controlling-robot/html.xml
|
||||
if (isNoindex) {
|
||||
return false;
|
||||
}
|
||||
const isServerSideExclude = text === '<!--sse-->' || text === '<!--/sse-->';
|
||||
// Don't remove sse comments.
|
||||
// See: https://support.cloudflare.com/hc/en-us/articles/200170036-What-does-Server-Side-Excludes-SSE-do-
|
||||
if (isServerSideExclude) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/Conditional_comment
|
||||
if ((0, _helpers.isConditionalComment)(text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Hexo: https://hexo.io/docs/tag-plugins#Post-Excerpt
|
||||
// Hugo: https://gohugo.io/content-management/summaries/#manual-summary-splitting
|
||||
// WordPress: https://wordpress.com/support/wordpress-editor/blocks/more-block/2/
|
||||
// Jekyll: https://jekyllrb.com/docs/posts/#post-excerpts
|
||||
const isCMSExcerptComment = MATCH_EXCERPT_REGEXP.test(text);
|
||||
if (isCMSExcerptComment) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (isMatcher(removeType)) {
|
||||
return isMatch(text, removeType);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function isMatch(input, matcher) {
|
||||
if (matcher instanceof RegExp) {
|
||||
return matcher.test(input);
|
||||
}
|
||||
if (typeof matcher === 'function') {
|
||||
return Boolean(matcher(input));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function isMatcher(matcher) {
|
||||
if (matcher instanceof RegExp || typeof matcher === 'function') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
92
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeComments.mjs
generated
vendored
Normal file
92
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeComments.mjs
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
import { isComment, isConditionalComment } from '../helpers.mjs';
|
||||
|
||||
const MATCH_EXCERPT_REGEXP = /<!-- ?more ?-->/i;
|
||||
|
||||
/** Removes HTML comments */
|
||||
export function onNode(options, removeType) {
|
||||
if (removeType !== 'all' && removeType !== 'safe' && !isMatcher(removeType)) {
|
||||
removeType = 'safe';
|
||||
}
|
||||
return (node) => {
|
||||
if (isCommentToRemove(node, removeType)) {
|
||||
return '';
|
||||
}
|
||||
return node;
|
||||
};
|
||||
}
|
||||
|
||||
export function onContent(options, removeType) {
|
||||
if (removeType !== 'all' && removeType !== 'safe' && !isMatcher(removeType)) {
|
||||
removeType = 'safe';
|
||||
}
|
||||
return (contents) => {
|
||||
return contents.filter(content => ! isCommentToRemove(content, removeType));
|
||||
};
|
||||
}
|
||||
|
||||
function isCommentToRemove(text, removeType) {
|
||||
if (typeof text !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! isComment(text)) {
|
||||
// Not HTML comment
|
||||
return false;
|
||||
}
|
||||
|
||||
if (removeType === 'safe') {
|
||||
const isNoindex = text === '<!--noindex-->' || text === '<!--/noindex-->';
|
||||
// Don't remove noindex comments.
|
||||
// See: https://yandex.com/support/webmaster/controlling-robot/html.xml
|
||||
if (isNoindex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const isServerSideExclude = text === '<!--sse-->' || text === '<!--/sse-->';
|
||||
// Don't remove sse comments.
|
||||
// See: https://support.cloudflare.com/hc/en-us/articles/200170036-What-does-Server-Side-Excludes-SSE-do-
|
||||
if (isServerSideExclude) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/Conditional_comment
|
||||
if (isConditionalComment(text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Hexo: https://hexo.io/docs/tag-plugins#Post-Excerpt
|
||||
// Hugo: https://gohugo.io/content-management/summaries/#manual-summary-splitting
|
||||
// WordPress: https://wordpress.com/support/wordpress-editor/blocks/more-block/2/
|
||||
// Jekyll: https://jekyllrb.com/docs/posts/#post-excerpts
|
||||
const isCMSExcerptComment = MATCH_EXCERPT_REGEXP.test(text);
|
||||
if (isCMSExcerptComment) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isMatcher(removeType)) {
|
||||
return isMatch(text, removeType);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function isMatch(input, matcher) {
|
||||
if (matcher instanceof RegExp) {
|
||||
return matcher.test(input);
|
||||
}
|
||||
|
||||
if (typeof matcher === 'function') {
|
||||
return Boolean(matcher(input));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function isMatcher(matcher) {
|
||||
if (matcher instanceof RegExp || typeof matcher === 'function') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
72
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeEmptyAttributes.cjs
generated
vendored
Normal file
72
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeEmptyAttributes.cjs
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.onAttrs = onAttrs;
|
||||
var _helpers = require("../helpers.cjs");
|
||||
const safeToRemoveAttrs = {
|
||||
id: null,
|
||||
class: null,
|
||||
style: null,
|
||||
title: null,
|
||||
lang: null,
|
||||
dir: null,
|
||||
abbr: ['th'],
|
||||
accept: ['input'],
|
||||
'accept-charset': ['form'],
|
||||
charset: ['meta', 'script'],
|
||||
action: ['form'],
|
||||
cols: ['textarea'],
|
||||
colspan: ['td', 'th'],
|
||||
coords: ['area'],
|
||||
dirname: ['input', 'textarea'],
|
||||
dropzone: null,
|
||||
headers: ['td', 'th'],
|
||||
form: ['button', 'fieldset', 'input', 'keygen', 'object', 'output', 'select', 'textarea'],
|
||||
formaction: ['button', 'input'],
|
||||
height: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video'],
|
||||
high: 'meter',
|
||||
href: 'link',
|
||||
list: 'input',
|
||||
low: 'meter',
|
||||
manifest: 'html',
|
||||
max: ['meter', 'progress'],
|
||||
maxLength: ['input', 'textarea'],
|
||||
menu: 'button',
|
||||
min: 'meter',
|
||||
minLength: ['input', 'textarea'],
|
||||
name: ['button', 'fieldset', 'input', 'keygen', 'output', 'select', 'textarea', 'form', 'map', 'meta', 'param', 'slot'],
|
||||
pattern: ['input'],
|
||||
ping: ['a', 'area'],
|
||||
placeholder: ['input', 'textarea'],
|
||||
poster: ['video'],
|
||||
rel: ['a', 'area', 'link'],
|
||||
rows: 'textarea',
|
||||
rowspan: ['td', 'th'],
|
||||
size: ['input', 'select'],
|
||||
span: ['col', 'colgroup'],
|
||||
src: ['audio', 'embed', 'iframe', 'img', 'input', 'script', 'source', 'track', 'video'],
|
||||
start: 'ol',
|
||||
tabindex: null,
|
||||
type: ['a', 'link', 'button', 'embed', 'object', 'script', 'source', 'style', 'input', 'menu', 'menuitem', 'ol'],
|
||||
value: ['button', 'input', 'li'],
|
||||
width: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video']
|
||||
};
|
||||
function onAttrs() {
|
||||
return (attrs, node) => {
|
||||
const newAttrs = {
|
||||
...attrs
|
||||
};
|
||||
Object.entries(attrs).forEach(([attrName, attrValue]) => {
|
||||
if ((0, _helpers.isEventHandler)(attrName) || Object.hasOwnProperty.call(safeToRemoveAttrs, attrName) && (safeToRemoveAttrs[attrName] === null || safeToRemoveAttrs[attrName].includes(node.tag))) {
|
||||
if (typeof attrValue === 'string') {
|
||||
if (attrValue === '' || attrValue.trim() === '') {
|
||||
delete newAttrs[attrName];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return newAttrs;
|
||||
};
|
||||
}
|
||||
121
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeEmptyAttributes.mjs
generated
vendored
Normal file
121
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeEmptyAttributes.mjs
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
import { isEventHandler } from '../helpers.mjs';
|
||||
|
||||
const safeToRemoveAttrs = {
|
||||
id: null,
|
||||
class: null,
|
||||
style: null,
|
||||
title: null,
|
||||
lang: null,
|
||||
dir: null,
|
||||
abbr: ['th'],
|
||||
accept: ['input'],
|
||||
'accept-charset': ['form'],
|
||||
charset: ['meta', 'script'],
|
||||
action: ['form'],
|
||||
cols: ['textarea'],
|
||||
colspan: ['td', 'th'],
|
||||
coords: ['area'],
|
||||
dirname: ['input', 'textarea'],
|
||||
dropzone: null,
|
||||
headers: ['td', 'th'],
|
||||
form: [
|
||||
'button',
|
||||
'fieldset',
|
||||
'input',
|
||||
'keygen',
|
||||
'object',
|
||||
'output',
|
||||
'select',
|
||||
'textarea'
|
||||
],
|
||||
formaction: ['button', 'input'],
|
||||
height: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video'],
|
||||
high: 'meter',
|
||||
href: 'link',
|
||||
list: 'input',
|
||||
low: 'meter',
|
||||
manifest: 'html',
|
||||
max: ['meter', 'progress'],
|
||||
maxLength: ['input', 'textarea'],
|
||||
menu: 'button',
|
||||
min: 'meter',
|
||||
minLength: ['input', 'textarea'],
|
||||
name: [
|
||||
'button',
|
||||
'fieldset',
|
||||
'input',
|
||||
'keygen',
|
||||
'output',
|
||||
'select',
|
||||
'textarea',
|
||||
'form',
|
||||
'map',
|
||||
'meta',
|
||||
'param',
|
||||
'slot'
|
||||
],
|
||||
pattern: ['input'],
|
||||
ping: ['a', 'area'],
|
||||
placeholder: ['input', 'textarea'],
|
||||
poster: ['video'],
|
||||
rel: ['a', 'area', 'link'],
|
||||
rows: 'textarea',
|
||||
rowspan: ['td', 'th'],
|
||||
size: ['input', 'select'],
|
||||
span: ['col', 'colgroup'],
|
||||
src: [
|
||||
'audio',
|
||||
'embed',
|
||||
'iframe',
|
||||
'img',
|
||||
'input',
|
||||
'script',
|
||||
'source',
|
||||
'track',
|
||||
'video'
|
||||
],
|
||||
start: 'ol',
|
||||
tabindex: null,
|
||||
type: [
|
||||
'a',
|
||||
'link',
|
||||
'button',
|
||||
'embed',
|
||||
'object',
|
||||
'script',
|
||||
'source',
|
||||
'style',
|
||||
'input',
|
||||
'menu',
|
||||
'menuitem',
|
||||
'ol'
|
||||
],
|
||||
value: ['button', 'input', 'li'],
|
||||
width: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video']
|
||||
};
|
||||
|
||||
export function onAttrs() {
|
||||
return (attrs, node) => {
|
||||
const newAttrs = { ...attrs };
|
||||
Object.entries(attrs).forEach(([attrName, attrValue]) => {
|
||||
if (
|
||||
isEventHandler(attrName)
|
||||
|| (
|
||||
Object.hasOwnProperty.call(safeToRemoveAttrs, attrName)
|
||||
&& (
|
||||
safeToRemoveAttrs[attrName] === null
|
||||
|| safeToRemoveAttrs[attrName].includes(node.tag)
|
||||
)
|
||||
)
|
||||
) {
|
||||
if (typeof attrValue === 'string') {
|
||||
if (attrValue === '' || attrValue.trim() === '') {
|
||||
delete newAttrs[attrName];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return newAttrs;
|
||||
};
|
||||
}
|
||||
183
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeOptionalTags.cjs
generated
vendored
Normal file
183
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeOptionalTags.cjs
generated
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = removeOptionalTags;
|
||||
var _helpers = require("../helpers.cjs");
|
||||
const startWithWhitespacePattern = /^\s+/;
|
||||
const bodyStartTagCantBeOmittedWithFirstChildTags = new Set(['meta', 'link', 'script', 'style']);
|
||||
const tbodyStartTagCantBeOmittedWithPrecededTags = new Set(['tbody', 'thead', 'tfoot']);
|
||||
const tbodyEndTagCantBeOmittedWithFollowedTags = new Set(['tbody', 'tfoot']);
|
||||
function isEmptyTextNode(node) {
|
||||
if (typeof node === 'string' && node.trim() === '') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function isEmptyNode(node) {
|
||||
if (!node.content) {
|
||||
return true;
|
||||
}
|
||||
if (node.content.length) {
|
||||
return !node.content.filter(n => typeof n === 'string' && isEmptyTextNode(n) ? false : true).length;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function getFirstChildTag(node, nonEmpty = true) {
|
||||
if (node.content && node.content.length) {
|
||||
if (nonEmpty) {
|
||||
for (const childNode of node.content) {
|
||||
if (childNode.tag) return childNode;
|
||||
if (typeof childNode === 'string' && !isEmptyTextNode(childNode)) return childNode;
|
||||
}
|
||||
} else {
|
||||
return node.content[0] || null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function getPrevNode(tree, currentNodeIndex, nonEmpty = false) {
|
||||
if (nonEmpty) {
|
||||
for (let i = currentNodeIndex - 1; i >= 0; i--) {
|
||||
const node = tree[i];
|
||||
if (node.tag) return node;
|
||||
if (typeof node === 'string' && !isEmptyTextNode(node)) return node;
|
||||
}
|
||||
} else {
|
||||
return tree[currentNodeIndex - 1] || null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function getNextNode(tree, currentNodeIndex, nonEmpty = false) {
|
||||
if (nonEmpty) {
|
||||
for (let i = currentNodeIndex + 1; i < tree.length; i++) {
|
||||
const node = tree[i];
|
||||
if (node.tag) return node;
|
||||
if (typeof node === 'string' && !isEmptyTextNode(node)) return node;
|
||||
}
|
||||
} else {
|
||||
return tree[currentNodeIndex + 1] || null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Specification https://html.spec.whatwg.org/multipage/syntax.html#optional-tags
|
||||
/** Remove optional tag in the DOM */
|
||||
function removeOptionalTags(tree) {
|
||||
tree.forEach((node, index) => {
|
||||
if (!node.tag) return node;
|
||||
if (node.attrs && Object.keys(node.attrs).length) return node;
|
||||
|
||||
// const prevNode = getPrevNode(tree, index);
|
||||
const prevNonEmptyNode = getPrevNode(tree, index, true);
|
||||
const nextNode = getNextNode(tree, index);
|
||||
const nextNonEmptyNode = getNextNode(tree, index, true);
|
||||
const firstChildNode = getFirstChildTag(node, false);
|
||||
const firstNonEmptyChildNode = getFirstChildTag(node);
|
||||
|
||||
/**
|
||||
* An "html" element's start tag may be omitted if the first thing inside the "html" element is not a comment.
|
||||
* An "html" element's end tag may be omitted if the "html" element is not IMMEDIATELY followed by a comment.
|
||||
*/
|
||||
if (node.tag === 'html') {
|
||||
let isHtmlStartTagCanBeOmitted = true;
|
||||
let isHtmlEndTagCanBeOmitted = true;
|
||||
if (typeof firstNonEmptyChildNode === 'string' && (0, _helpers.isComment)(firstNonEmptyChildNode)) {
|
||||
isHtmlStartTagCanBeOmitted = false;
|
||||
}
|
||||
if (typeof nextNonEmptyNode === 'string' && (0, _helpers.isComment)(nextNonEmptyNode)) {
|
||||
isHtmlEndTagCanBeOmitted = false;
|
||||
}
|
||||
if (isHtmlStartTagCanBeOmitted && isHtmlEndTagCanBeOmitted) {
|
||||
node.tag = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A "head" element's start tag may be omitted if the element is empty, or if the first thing inside the "head" element is an element.
|
||||
* A "head" element's end tag may be omitted if the "head" element is not IMMEDIATELY followed by ASCII whitespace or a comment.
|
||||
*/
|
||||
if (node.tag === 'head') {
|
||||
let isHeadStartTagCanBeOmitted = false;
|
||||
let isHeadEndTagCanBeOmitted = true;
|
||||
if (isEmptyNode(node) || firstNonEmptyChildNode && firstNonEmptyChildNode.tag) {
|
||||
isHeadStartTagCanBeOmitted = true;
|
||||
}
|
||||
if (nextNode && typeof nextNode === 'string' && startWithWhitespacePattern.test(nextNode) || nextNonEmptyNode && typeof nextNonEmptyNode === 'string' && (0, _helpers.isComment)(nextNode)) {
|
||||
isHeadEndTagCanBeOmitted = false;
|
||||
}
|
||||
if (isHeadStartTagCanBeOmitted && isHeadEndTagCanBeOmitted) {
|
||||
node.tag = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A "body" element's start tag may be omitted if the element is empty, or if the first thing inside the "body" element is not ASCII whitespace or a comment, except if the first thing inside the "body" element is a "meta", "link", "script", "style", or "template" element.
|
||||
* A "body" element's end tag may be omitted if the "body" element is not IMMEDIATELY followed by a comment.
|
||||
*/
|
||||
if (node.tag === 'body') {
|
||||
let isBodyStartTagCanBeOmitted = true;
|
||||
let isBodyEndTagCanBeOmitted = true;
|
||||
if (typeof firstChildNode === 'string' && startWithWhitespacePattern.test(firstChildNode) || typeof firstNonEmptyChildNode === 'string' && (0, _helpers.isComment)(firstNonEmptyChildNode)) {
|
||||
isBodyStartTagCanBeOmitted = false;
|
||||
}
|
||||
if (firstNonEmptyChildNode && firstNonEmptyChildNode.tag && bodyStartTagCantBeOmittedWithFirstChildTags.has(firstNonEmptyChildNode.tag)) {
|
||||
isBodyStartTagCanBeOmitted = false;
|
||||
}
|
||||
if (nextNode && typeof nextNode === 'string' && (0, _helpers.isComment)(nextNode)) {
|
||||
isBodyEndTagCanBeOmitted = false;
|
||||
}
|
||||
if (isBodyStartTagCanBeOmitted && isBodyEndTagCanBeOmitted) {
|
||||
node.tag = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A "colgroup" element's start tag may be omitted if the first thing inside the "colgroup" element is a "col" element, and if the element is not IMMEDIATELY preceded by another "colgroup" element. It can't be omitted if the element is empty.
|
||||
* A "colgroup" element's end tag may be omitted if the "colgroup" element is not IMMEDIATELY followed by ASCII whitespace or a comment.
|
||||
*/
|
||||
if (node.tag === 'colgroup') {
|
||||
let isColgroupStartTagCanBeOmitted = false;
|
||||
let isColgroupEndTagCanBeOmitted = true;
|
||||
if (firstNonEmptyChildNode && firstNonEmptyChildNode.tag && firstNonEmptyChildNode.tag === 'col') {
|
||||
isColgroupStartTagCanBeOmitted = true;
|
||||
}
|
||||
if (prevNonEmptyNode && prevNonEmptyNode.tag && prevNonEmptyNode.tag === 'colgroup') {
|
||||
isColgroupStartTagCanBeOmitted = false;
|
||||
}
|
||||
if (nextNode && typeof nextNode === 'string' && startWithWhitespacePattern.test(nextNode) || nextNonEmptyNode && typeof nextNonEmptyNode === 'string' && (0, _helpers.isComment)(nextNonEmptyNode)) {
|
||||
isColgroupEndTagCanBeOmitted = false;
|
||||
}
|
||||
if (isColgroupStartTagCanBeOmitted && isColgroupEndTagCanBeOmitted) {
|
||||
node.tag = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A "tbody" element's start tag may be omitted if the first thing inside the "tbody" element is a "tr" element, and if the element is not immediately preceded by another "tbody", "thead" or "tfoot" element. It can't be omitted if the element is empty.
|
||||
* A "tbody" element's end tag may be omitted if the "tbody" element is not IMMEDIATELY followed by a "tbody" or "tfoot" element.
|
||||
*/
|
||||
if (node.tag === 'tbody') {
|
||||
let isTbodyStartTagCanBeOmitted = false;
|
||||
let isTbodyEndTagCanBeOmitted = true;
|
||||
if (firstNonEmptyChildNode && firstNonEmptyChildNode.tag && firstNonEmptyChildNode.tag === 'tr') {
|
||||
isTbodyStartTagCanBeOmitted = true;
|
||||
}
|
||||
if (prevNonEmptyNode && prevNonEmptyNode.tag && tbodyStartTagCantBeOmittedWithPrecededTags.has(prevNonEmptyNode.tag)) {
|
||||
isTbodyStartTagCanBeOmitted = false;
|
||||
}
|
||||
if (nextNonEmptyNode && nextNonEmptyNode.tag && tbodyEndTagCantBeOmittedWithFollowedTags.has(nextNonEmptyNode.tag)) {
|
||||
isTbodyEndTagCanBeOmitted = false;
|
||||
}
|
||||
if (isTbodyStartTagCanBeOmitted && isTbodyEndTagCanBeOmitted) {
|
||||
node.tag = false;
|
||||
}
|
||||
}
|
||||
if (node.content && node.content.length) {
|
||||
removeOptionalTags(node.content);
|
||||
}
|
||||
return node;
|
||||
});
|
||||
return tree;
|
||||
}
|
||||
225
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeOptionalTags.mjs
generated
vendored
Normal file
225
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeOptionalTags.mjs
generated
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
import { isComment } from '../helpers.mjs';
|
||||
|
||||
const startWithWhitespacePattern = /^\s+/;
|
||||
|
||||
const bodyStartTagCantBeOmittedWithFirstChildTags = new Set(['meta', 'link', 'script', 'style']);
|
||||
const tbodyStartTagCantBeOmittedWithPrecededTags = new Set(['tbody', 'thead', 'tfoot']);
|
||||
const tbodyEndTagCantBeOmittedWithFollowedTags = new Set(['tbody', 'tfoot']);
|
||||
|
||||
function isEmptyTextNode(node) {
|
||||
if (typeof node === 'string' && node.trim() === '') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function isEmptyNode(node) {
|
||||
if (!node.content) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (node.content.length) {
|
||||
return !node.content.filter(n => typeof n === 'string' && isEmptyTextNode(n) ? false : true).length;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getFirstChildTag(node, nonEmpty = true) {
|
||||
if (node.content && node.content.length) {
|
||||
if (nonEmpty) {
|
||||
for (const childNode of node.content) {
|
||||
if (childNode.tag) return childNode;
|
||||
if (typeof childNode === 'string' && !isEmptyTextNode(childNode)) return childNode;
|
||||
}
|
||||
} else {
|
||||
return node.content[0] || null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getPrevNode(tree, currentNodeIndex, nonEmpty = false) {
|
||||
if (nonEmpty) {
|
||||
for (let i = currentNodeIndex - 1; i >= 0; i--) {
|
||||
const node = tree[i];
|
||||
if (node.tag) return node;
|
||||
if (typeof node === 'string' && !isEmptyTextNode(node)) return node;
|
||||
}
|
||||
} else {
|
||||
return tree[currentNodeIndex - 1] || null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getNextNode(tree, currentNodeIndex, nonEmpty = false) {
|
||||
if (nonEmpty) {
|
||||
for (let i = currentNodeIndex + 1; i < tree.length; i++) {
|
||||
const node = tree[i];
|
||||
if (node.tag) return node;
|
||||
if (typeof node === 'string' && !isEmptyTextNode(node)) return node;
|
||||
}
|
||||
} else {
|
||||
return tree[currentNodeIndex + 1] || null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Specification https://html.spec.whatwg.org/multipage/syntax.html#optional-tags
|
||||
/** Remove optional tag in the DOM */
|
||||
export default function removeOptionalTags(tree) {
|
||||
tree.forEach((node, index) => {
|
||||
if (!node.tag) return node;
|
||||
|
||||
if (node.attrs && Object.keys(node.attrs).length) return node;
|
||||
|
||||
// const prevNode = getPrevNode(tree, index);
|
||||
const prevNonEmptyNode = getPrevNode(tree, index, true);
|
||||
const nextNode = getNextNode(tree, index);
|
||||
const nextNonEmptyNode = getNextNode(tree, index, true);
|
||||
const firstChildNode = getFirstChildTag(node, false);
|
||||
const firstNonEmptyChildNode = getFirstChildTag(node);
|
||||
|
||||
/**
|
||||
* An "html" element's start tag may be omitted if the first thing inside the "html" element is not a comment.
|
||||
* An "html" element's end tag may be omitted if the "html" element is not IMMEDIATELY followed by a comment.
|
||||
*/
|
||||
if (node.tag === 'html') {
|
||||
let isHtmlStartTagCanBeOmitted = true;
|
||||
let isHtmlEndTagCanBeOmitted = true;
|
||||
|
||||
if (typeof firstNonEmptyChildNode === 'string' && isComment(firstNonEmptyChildNode)) {
|
||||
isHtmlStartTagCanBeOmitted = false;
|
||||
}
|
||||
|
||||
if (typeof nextNonEmptyNode === 'string' && isComment(nextNonEmptyNode)) {
|
||||
isHtmlEndTagCanBeOmitted = false;
|
||||
}
|
||||
|
||||
if (isHtmlStartTagCanBeOmitted && isHtmlEndTagCanBeOmitted) {
|
||||
node.tag = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A "head" element's start tag may be omitted if the element is empty, or if the first thing inside the "head" element is an element.
|
||||
* A "head" element's end tag may be omitted if the "head" element is not IMMEDIATELY followed by ASCII whitespace or a comment.
|
||||
*/
|
||||
if (node.tag === 'head') {
|
||||
let isHeadStartTagCanBeOmitted = false;
|
||||
let isHeadEndTagCanBeOmitted = true;
|
||||
|
||||
if (
|
||||
isEmptyNode(node) ||
|
||||
firstNonEmptyChildNode && firstNonEmptyChildNode.tag
|
||||
) {
|
||||
isHeadStartTagCanBeOmitted = true;
|
||||
}
|
||||
|
||||
if (
|
||||
(nextNode && typeof nextNode === 'string' && startWithWhitespacePattern.test(nextNode)) ||
|
||||
(nextNonEmptyNode && typeof nextNonEmptyNode === 'string' && isComment(nextNode))
|
||||
) {
|
||||
isHeadEndTagCanBeOmitted = false;
|
||||
}
|
||||
|
||||
if (isHeadStartTagCanBeOmitted && isHeadEndTagCanBeOmitted) {
|
||||
node.tag = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A "body" element's start tag may be omitted if the element is empty, or if the first thing inside the "body" element is not ASCII whitespace or a comment, except if the first thing inside the "body" element is a "meta", "link", "script", "style", or "template" element.
|
||||
* A "body" element's end tag may be omitted if the "body" element is not IMMEDIATELY followed by a comment.
|
||||
*/
|
||||
if (node.tag === 'body') {
|
||||
let isBodyStartTagCanBeOmitted = true;
|
||||
let isBodyEndTagCanBeOmitted = true;
|
||||
|
||||
if (
|
||||
(typeof firstChildNode === 'string' && startWithWhitespacePattern.test(firstChildNode)) ||
|
||||
(typeof firstNonEmptyChildNode === 'string' && isComment(firstNonEmptyChildNode))
|
||||
) {
|
||||
isBodyStartTagCanBeOmitted = false;
|
||||
}
|
||||
|
||||
if (firstNonEmptyChildNode && firstNonEmptyChildNode.tag && bodyStartTagCantBeOmittedWithFirstChildTags.has(firstNonEmptyChildNode.tag)) {
|
||||
isBodyStartTagCanBeOmitted = false;
|
||||
}
|
||||
|
||||
if (nextNode && typeof nextNode === 'string' && isComment(nextNode)) {
|
||||
isBodyEndTagCanBeOmitted = false;
|
||||
}
|
||||
|
||||
if (isBodyStartTagCanBeOmitted && isBodyEndTagCanBeOmitted) {
|
||||
node.tag = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A "colgroup" element's start tag may be omitted if the first thing inside the "colgroup" element is a "col" element, and if the element is not IMMEDIATELY preceded by another "colgroup" element. It can't be omitted if the element is empty.
|
||||
* A "colgroup" element's end tag may be omitted if the "colgroup" element is not IMMEDIATELY followed by ASCII whitespace or a comment.
|
||||
*/
|
||||
if (node.tag === 'colgroup') {
|
||||
let isColgroupStartTagCanBeOmitted = false;
|
||||
let isColgroupEndTagCanBeOmitted = true;
|
||||
|
||||
if (firstNonEmptyChildNode && firstNonEmptyChildNode.tag && firstNonEmptyChildNode.tag === 'col') {
|
||||
isColgroupStartTagCanBeOmitted = true;
|
||||
}
|
||||
|
||||
if (prevNonEmptyNode && prevNonEmptyNode.tag && prevNonEmptyNode.tag === 'colgroup') {
|
||||
isColgroupStartTagCanBeOmitted = false;
|
||||
}
|
||||
|
||||
if (
|
||||
(nextNode && typeof nextNode === 'string' && startWithWhitespacePattern.test(nextNode)) ||
|
||||
(nextNonEmptyNode && typeof nextNonEmptyNode === 'string' && isComment(nextNonEmptyNode))
|
||||
) {
|
||||
isColgroupEndTagCanBeOmitted = false;
|
||||
}
|
||||
|
||||
if (isColgroupStartTagCanBeOmitted && isColgroupEndTagCanBeOmitted) {
|
||||
node.tag = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A "tbody" element's start tag may be omitted if the first thing inside the "tbody" element is a "tr" element, and if the element is not immediately preceded by another "tbody", "thead" or "tfoot" element. It can't be omitted if the element is empty.
|
||||
* A "tbody" element's end tag may be omitted if the "tbody" element is not IMMEDIATELY followed by a "tbody" or "tfoot" element.
|
||||
*/
|
||||
if (node.tag === 'tbody') {
|
||||
let isTbodyStartTagCanBeOmitted = false;
|
||||
let isTbodyEndTagCanBeOmitted = true;
|
||||
|
||||
if (firstNonEmptyChildNode && firstNonEmptyChildNode.tag && firstNonEmptyChildNode.tag === 'tr') {
|
||||
isTbodyStartTagCanBeOmitted = true;
|
||||
}
|
||||
|
||||
if (prevNonEmptyNode && prevNonEmptyNode.tag && tbodyStartTagCantBeOmittedWithPrecededTags.has(prevNonEmptyNode.tag)) {
|
||||
isTbodyStartTagCanBeOmitted = false;
|
||||
}
|
||||
|
||||
if (nextNonEmptyNode && nextNonEmptyNode.tag && tbodyEndTagCantBeOmittedWithFollowedTags.has(nextNonEmptyNode.tag)) {
|
||||
isTbodyEndTagCanBeOmitted = false;
|
||||
}
|
||||
|
||||
if (isTbodyStartTagCanBeOmitted && isTbodyEndTagCanBeOmitted) {
|
||||
node.tag = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.content && node.content.length) {
|
||||
removeOptionalTags(node.content);
|
||||
}
|
||||
|
||||
return node;
|
||||
});
|
||||
|
||||
return tree;
|
||||
}
|
||||
112
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeRedundantAttributes.cjs
generated
vendored
Normal file
112
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeRedundantAttributes.cjs
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.onAttrs = onAttrs;
|
||||
exports.redundantScriptTypes = void 0;
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#JavaScript_types
|
||||
const redundantScriptTypes = exports.redundantScriptTypes = new Set(['application/javascript', 'application/ecmascript', 'application/x-ecmascript', 'application/x-javascript', 'text/javascript', 'text/ecmascript', 'text/javascript1.0', 'text/javascript1.1', 'text/javascript1.2', 'text/javascript1.3', 'text/javascript1.4', 'text/javascript1.5', 'text/jscript', 'text/livescript', 'text/x-ecmascript', 'text/x-javascript']);
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#missing-value-default
|
||||
const missingValueDefaultAttributes = {
|
||||
'form': {
|
||||
'method': 'get'
|
||||
},
|
||||
input: {
|
||||
type: 'text'
|
||||
},
|
||||
button: {
|
||||
// https://html.spec.whatwg.org/multipage/form-elements.html#attr-button-type
|
||||
type: 'submit'
|
||||
},
|
||||
'script': {
|
||||
'language': 'javascript',
|
||||
'type': attrs => {
|
||||
for (const [attrName, attrValue] of Object.entries(attrs)) {
|
||||
if (attrName.toLowerCase() !== 'type') {
|
||||
continue;
|
||||
}
|
||||
return redundantScriptTypes.has(attrValue);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
// Remove attribute if the function returns false
|
||||
'charset': attrs => {
|
||||
// The charset attribute only really makes sense on “external” SCRIPT elements:
|
||||
// http://perfectionkills.com/optimizing-html/#8_script_charset
|
||||
return !attrs.src;
|
||||
}
|
||||
},
|
||||
'style': {
|
||||
'media': 'all',
|
||||
'type': 'text/css'
|
||||
},
|
||||
'link': {
|
||||
media: 'all',
|
||||
'type': attrs => {
|
||||
// https://html.spec.whatwg.org/multipage/links.html#link-type-stylesheet
|
||||
let isRelStyleSheet = false;
|
||||
let isTypeTextCSS = false;
|
||||
if (attrs) {
|
||||
for (const [attrName, attrValue] of Object.entries(attrs)) {
|
||||
if (attrName.toLowerCase() === 'rel' && attrValue === 'stylesheet') {
|
||||
isRelStyleSheet = true;
|
||||
}
|
||||
if (attrName.toLowerCase() === 'type' && attrValue === 'text/css') {
|
||||
isTypeTextCSS = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only "text/css" is redudant for link[rel=stylesheet]. Otherwise "type" shouldn't be removed
|
||||
return isRelStyleSheet && isTypeTextCSS;
|
||||
}
|
||||
},
|
||||
// See: https://html.spec.whatwg.org/#lazy-loading-attributes
|
||||
img: {
|
||||
'loading': 'eager',
|
||||
// https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-decoding
|
||||
decoding: 'auto'
|
||||
},
|
||||
iframe: {
|
||||
'loading': 'eager'
|
||||
},
|
||||
// https://html.spec.whatwg.org/multipage/media.html#htmltrackelement
|
||||
track: {
|
||||
kind: 'subtitles'
|
||||
},
|
||||
textarea: {
|
||||
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-wrap
|
||||
wrap: 'soft'
|
||||
},
|
||||
area: {
|
||||
// https://html.spec.whatwg.org/multipage/image-maps.html#attr-area-shape
|
||||
shape: 'rect'
|
||||
}
|
||||
};
|
||||
const tagsHaveMissingValueDefaultAttributes = new Set(Object.keys(missingValueDefaultAttributes));
|
||||
|
||||
/** Removes redundant attributes */
|
||||
function onAttrs() {
|
||||
return (attrs, node) => {
|
||||
if (!node.tag) return attrs;
|
||||
const newAttrs = attrs;
|
||||
if (tagsHaveMissingValueDefaultAttributes.has(node.tag)) {
|
||||
const tagRedundantAttributes = missingValueDefaultAttributes[node.tag];
|
||||
for (const redundantAttributeName of Object.keys(tagRedundantAttributes)) {
|
||||
let tagRedundantAttributeValue = tagRedundantAttributes[redundantAttributeName];
|
||||
let isRemove = false;
|
||||
if (typeof tagRedundantAttributeValue === 'function') {
|
||||
isRemove = tagRedundantAttributeValue(attrs);
|
||||
} else if (attrs[redundantAttributeName] === tagRedundantAttributeValue) {
|
||||
isRemove = true;
|
||||
}
|
||||
if (isRemove) {
|
||||
delete newAttrs[redundantAttributeName];
|
||||
}
|
||||
}
|
||||
}
|
||||
return newAttrs;
|
||||
};
|
||||
}
|
||||
141
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeRedundantAttributes.mjs
generated
vendored
Normal file
141
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeRedundantAttributes.mjs
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#JavaScript_types
|
||||
export const redundantScriptTypes = new Set([
|
||||
'application/javascript',
|
||||
'application/ecmascript',
|
||||
'application/x-ecmascript',
|
||||
'application/x-javascript',
|
||||
'text/javascript',
|
||||
'text/ecmascript',
|
||||
'text/javascript1.0',
|
||||
'text/javascript1.1',
|
||||
'text/javascript1.2',
|
||||
'text/javascript1.3',
|
||||
'text/javascript1.4',
|
||||
'text/javascript1.5',
|
||||
'text/jscript',
|
||||
'text/livescript',
|
||||
'text/x-ecmascript',
|
||||
'text/x-javascript'
|
||||
]);
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#missing-value-default
|
||||
const missingValueDefaultAttributes = {
|
||||
'form': {
|
||||
'method': 'get'
|
||||
},
|
||||
|
||||
input: {
|
||||
type: 'text'
|
||||
},
|
||||
|
||||
button: {
|
||||
// https://html.spec.whatwg.org/multipage/form-elements.html#attr-button-type
|
||||
type: 'submit'
|
||||
},
|
||||
|
||||
'script': {
|
||||
'language': 'javascript',
|
||||
'type': attrs => {
|
||||
for (const [attrName, attrValue] of Object.entries(attrs)) {
|
||||
if (attrName.toLowerCase() !== 'type') {
|
||||
continue;
|
||||
}
|
||||
|
||||
return redundantScriptTypes.has(attrValue);
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
// Remove attribute if the function returns false
|
||||
'charset': attrs => {
|
||||
// The charset attribute only really makes sense on “external” SCRIPT elements:
|
||||
// http://perfectionkills.com/optimizing-html/#8_script_charset
|
||||
return !attrs.src;
|
||||
}
|
||||
},
|
||||
|
||||
'style': {
|
||||
'media': 'all',
|
||||
'type': 'text/css'
|
||||
},
|
||||
|
||||
'link': {
|
||||
media: 'all',
|
||||
'type': attrs => {
|
||||
// https://html.spec.whatwg.org/multipage/links.html#link-type-stylesheet
|
||||
let isRelStyleSheet = false;
|
||||
let isTypeTextCSS = false;
|
||||
|
||||
if (attrs) {
|
||||
for (const [attrName, attrValue] of Object.entries(attrs)) {
|
||||
if (attrName.toLowerCase() === 'rel' && attrValue === 'stylesheet') {
|
||||
isRelStyleSheet = true;
|
||||
}
|
||||
if (attrName.toLowerCase() === 'type' && attrValue === 'text/css') {
|
||||
isTypeTextCSS = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only "text/css" is redudant for link[rel=stylesheet]. Otherwise "type" shouldn't be removed
|
||||
return isRelStyleSheet && isTypeTextCSS;
|
||||
}
|
||||
},
|
||||
|
||||
// See: https://html.spec.whatwg.org/#lazy-loading-attributes
|
||||
img: {
|
||||
'loading': 'eager',
|
||||
// https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-decoding
|
||||
decoding: 'auto'
|
||||
},
|
||||
iframe: {
|
||||
'loading': 'eager'
|
||||
},
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/media.html#htmltrackelement
|
||||
track: {
|
||||
kind: 'subtitles'
|
||||
},
|
||||
|
||||
textarea: {
|
||||
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-wrap
|
||||
wrap: 'soft'
|
||||
},
|
||||
|
||||
area: {
|
||||
// https://html.spec.whatwg.org/multipage/image-maps.html#attr-area-shape
|
||||
shape: 'rect'
|
||||
}
|
||||
};
|
||||
|
||||
const tagsHaveMissingValueDefaultAttributes = new Set(Object.keys(missingValueDefaultAttributes));
|
||||
|
||||
/** Removes redundant attributes */
|
||||
export function onAttrs() {
|
||||
return (attrs, node) => {
|
||||
if (!node.tag) return attrs;
|
||||
|
||||
const newAttrs = attrs;
|
||||
|
||||
if (tagsHaveMissingValueDefaultAttributes.has(node.tag)) {
|
||||
const tagRedundantAttributes = missingValueDefaultAttributes[node.tag];
|
||||
|
||||
for (const redundantAttributeName of Object.keys(tagRedundantAttributes)) {
|
||||
let tagRedundantAttributeValue = tagRedundantAttributes[redundantAttributeName];
|
||||
let isRemove = false;
|
||||
|
||||
if (typeof tagRedundantAttributeValue === 'function') {
|
||||
isRemove = tagRedundantAttributeValue(attrs);
|
||||
} else if (attrs[redundantAttributeName] === tagRedundantAttributeValue) {
|
||||
isRemove = true;
|
||||
}
|
||||
|
||||
if (isRemove) {
|
||||
delete newAttrs[redundantAttributeName];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newAttrs;
|
||||
};
|
||||
}
|
||||
113
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeUnusedCss.cjs
generated
vendored
Normal file
113
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeUnusedCss.cjs
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = removeUnusedCss;
|
||||
var _helpers = require("../helpers.cjs");
|
||||
// These options must be set and shouldn't be overriden to ensure uncss doesn't look at linked stylesheets.
|
||||
const uncssOptions = {
|
||||
ignoreSheets: [/\s*/],
|
||||
stylesheets: []
|
||||
};
|
||||
function processStyleNodeUnCSS(html, styleNode, uncssOptions, uncss) {
|
||||
const css = (0, _helpers.extractCssFromStyleNode)(styleNode);
|
||||
return runUncss(html, css, uncssOptions, uncss).then(css => {
|
||||
// uncss may have left some style tags empty
|
||||
if (css.trim().length === 0) {
|
||||
styleNode.tag = false;
|
||||
styleNode.content = [];
|
||||
return;
|
||||
}
|
||||
styleNode.content = [css];
|
||||
});
|
||||
}
|
||||
function runUncss(html, css, userOptions, uncss) {
|
||||
if (typeof userOptions !== 'object') {
|
||||
userOptions = {};
|
||||
}
|
||||
const options = {
|
||||
...userOptions,
|
||||
...uncssOptions
|
||||
};
|
||||
return new Promise((resolve, reject) => {
|
||||
options.raw = css;
|
||||
uncss(html, options, (error, output) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve(output);
|
||||
});
|
||||
});
|
||||
}
|
||||
const purgeFromHtml = function (tree) {
|
||||
// content is not used as we can directly used the parsed HTML,
|
||||
// making the process faster
|
||||
const selectors = [];
|
||||
tree.walk(node => {
|
||||
const classes = node.attrs && node.attrs.class && node.attrs.class.split(' ') || [];
|
||||
const ids = node.attrs && node.attrs.id && node.attrs.id.split(' ') || [];
|
||||
selectors.push(...classes, ...ids);
|
||||
node.tag && selectors.push(node.tag);
|
||||
return node;
|
||||
});
|
||||
return () => selectors;
|
||||
};
|
||||
function processStyleNodePurgeCSS(tree, styleNode, purgecssOptions, purgecss) {
|
||||
const css = (0, _helpers.extractCssFromStyleNode)(styleNode);
|
||||
return runPurgecss(tree, css, purgecssOptions, purgecss).then(css => {
|
||||
if (css.trim().length === 0) {
|
||||
styleNode.tag = false;
|
||||
styleNode.content = [];
|
||||
return;
|
||||
}
|
||||
styleNode.content = [css];
|
||||
});
|
||||
}
|
||||
function runPurgecss(tree, css, userOptions, purgecss) {
|
||||
if (typeof userOptions !== 'object') {
|
||||
userOptions = {};
|
||||
}
|
||||
const options = {
|
||||
...userOptions,
|
||||
content: [{
|
||||
raw: tree,
|
||||
extension: 'html'
|
||||
}],
|
||||
css: [{
|
||||
raw: css,
|
||||
extension: 'css'
|
||||
}],
|
||||
extractors: [{
|
||||
extractor: purgeFromHtml(tree),
|
||||
extensions: ['html']
|
||||
}]
|
||||
};
|
||||
return new purgecss.PurgeCSS().purge(options).then(result => {
|
||||
return result[0].css;
|
||||
});
|
||||
}
|
||||
|
||||
/** Remove unused CSS */
|
||||
async function removeUnusedCss(tree, options, userOptions) {
|
||||
const promises = [];
|
||||
const html = userOptions.tool !== 'purgeCSS' && tree.render(tree);
|
||||
const purgecss = await (0, _helpers.optionalImport)('purgecss');
|
||||
const uncss = await (0, _helpers.optionalImport)('uncss');
|
||||
tree.walk(node => {
|
||||
if ((0, _helpers.isStyleNode)(node)) {
|
||||
if (userOptions.tool === 'purgeCSS') {
|
||||
if (purgecss) {
|
||||
promises.push(processStyleNodePurgeCSS(tree, node, userOptions, purgecss));
|
||||
}
|
||||
} else {
|
||||
if (uncss) {
|
||||
promises.push(processStyleNodeUnCSS(html, node, userOptions, uncss));
|
||||
}
|
||||
}
|
||||
}
|
||||
return node;
|
||||
});
|
||||
return Promise.all(promises).then(() => tree);
|
||||
}
|
||||
122
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeUnusedCss.mjs
generated
vendored
Normal file
122
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/removeUnusedCss.mjs
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
import { isStyleNode, extractCssFromStyleNode, optionalImport } from '../helpers.mjs';
|
||||
|
||||
// These options must be set and shouldn't be overriden to ensure uncss doesn't look at linked stylesheets.
|
||||
const uncssOptions = {
|
||||
ignoreSheets: [/\s*/],
|
||||
stylesheets: [],
|
||||
};
|
||||
|
||||
function processStyleNodeUnCSS(html, styleNode, uncssOptions, uncss) {
|
||||
const css = extractCssFromStyleNode(styleNode);
|
||||
|
||||
return runUncss(html, css, uncssOptions, uncss).then(css => {
|
||||
// uncss may have left some style tags empty
|
||||
if (css.trim().length === 0) {
|
||||
styleNode.tag = false;
|
||||
styleNode.content = [];
|
||||
return;
|
||||
}
|
||||
styleNode.content = [css];
|
||||
});
|
||||
}
|
||||
|
||||
function runUncss(html, css, userOptions, uncss) {
|
||||
if (typeof userOptions !== 'object') {
|
||||
userOptions = {};
|
||||
}
|
||||
|
||||
const options = { ...userOptions, ...uncssOptions };
|
||||
return new Promise((resolve, reject) => {
|
||||
options.raw = css;
|
||||
uncss(html, options, (error, output) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve(output);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const purgeFromHtml = function (tree) {
|
||||
// content is not used as we can directly used the parsed HTML,
|
||||
// making the process faster
|
||||
const selectors = [];
|
||||
|
||||
tree.walk(node => {
|
||||
const classes = node.attrs && node.attrs.class && node.attrs.class.split(' ') || [];
|
||||
const ids = node.attrs && node.attrs.id && node.attrs.id.split(' ') || [];
|
||||
selectors.push(...classes, ...ids);
|
||||
node.tag && selectors.push(node.tag);
|
||||
return node;
|
||||
});
|
||||
|
||||
return () => selectors;
|
||||
};
|
||||
|
||||
function processStyleNodePurgeCSS(tree, styleNode, purgecssOptions, purgecss) {
|
||||
const css = extractCssFromStyleNode(styleNode);
|
||||
return runPurgecss(tree, css, purgecssOptions, purgecss)
|
||||
.then(css => {
|
||||
if (css.trim().length === 0) {
|
||||
styleNode.tag = false;
|
||||
styleNode.content = [];
|
||||
return;
|
||||
}
|
||||
styleNode.content = [css];
|
||||
});
|
||||
}
|
||||
|
||||
function runPurgecss(tree, css, userOptions, purgecss) {
|
||||
if (typeof userOptions !== 'object') {
|
||||
userOptions = {};
|
||||
}
|
||||
|
||||
const options = {
|
||||
...userOptions,
|
||||
content: [{
|
||||
raw: tree,
|
||||
extension: 'html'
|
||||
}],
|
||||
css: [{
|
||||
raw: css,
|
||||
extension: 'css'
|
||||
}],
|
||||
extractors: [{
|
||||
extractor: purgeFromHtml(tree),
|
||||
extensions: ['html']
|
||||
}]
|
||||
};
|
||||
|
||||
return new purgecss.PurgeCSS()
|
||||
.purge(options)
|
||||
.then((result) => {
|
||||
return result[0].css;
|
||||
});
|
||||
}
|
||||
|
||||
/** Remove unused CSS */
|
||||
export default async function removeUnusedCss(tree, options, userOptions) {
|
||||
const promises = [];
|
||||
const html = userOptions.tool !== 'purgeCSS' && tree.render(tree);
|
||||
|
||||
const purgecss = await optionalImport('purgecss');
|
||||
const uncss = await optionalImport('uncss');
|
||||
|
||||
tree.walk(node => {
|
||||
if (isStyleNode(node)) {
|
||||
if (userOptions.tool === 'purgeCSS') {
|
||||
if (purgecss) {
|
||||
promises.push(processStyleNodePurgeCSS(tree, node, userOptions, purgecss));
|
||||
}
|
||||
} else {
|
||||
if (uncss) {
|
||||
promises.push(processStyleNodeUnCSS(html, node, userOptions, uncss));
|
||||
}
|
||||
}
|
||||
}
|
||||
return node;
|
||||
});
|
||||
|
||||
return Promise.all(promises).then(() => tree);
|
||||
}
|
||||
100
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/sortAttributes.cjs
generated
vendored
Normal file
100
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/sortAttributes.cjs
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = sortAttributes;
|
||||
var _timsort = require("timsort");
|
||||
const validOptions = new Set(['frequency', 'alphabetical']);
|
||||
const processModuleOptions = options => {
|
||||
if (options === true) return 'alphabetical';
|
||||
return validOptions.has(options) ? options : false;
|
||||
};
|
||||
class AttributeTokenChain {
|
||||
constructor() {
|
||||
this.freqData = new Map(); // <attr, frequency>[]
|
||||
}
|
||||
|
||||
addFromNodeAttrs(nodeAttrs) {
|
||||
Object.keys(nodeAttrs).forEach(attrName => {
|
||||
const attrNameLower = attrName.toLowerCase();
|
||||
if (this.freqData.has(attrNameLower)) {
|
||||
this.freqData.set(attrNameLower, this.freqData.get(attrNameLower) + 1);
|
||||
} else {
|
||||
this.freqData.set(attrNameLower, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
createSortOrder() {
|
||||
let _sortOrder = [...this.freqData.entries()];
|
||||
(0, _timsort.sort)(_sortOrder, (a, b) => b[1] - a[1]);
|
||||
this.sortOrder = _sortOrder.map(i => i[0]);
|
||||
}
|
||||
sortFromNodeAttrs(nodeAttrs) {
|
||||
const newAttrs = {};
|
||||
|
||||
// Convert node.attrs attrName into lower case.
|
||||
const loweredNodeAttrs = {};
|
||||
Object.entries(nodeAttrs).forEach(([attrName, attrValue]) => {
|
||||
loweredNodeAttrs[attrName.toLowerCase()] = attrValue;
|
||||
});
|
||||
if (!this.sortOrder) {
|
||||
this.createSortOrder();
|
||||
}
|
||||
this.sortOrder.forEach(attrNameLower => {
|
||||
// The attrName inside "sortOrder" has been lowered
|
||||
if (loweredNodeAttrs[attrNameLower] != null) {
|
||||
newAttrs[attrNameLower] = loweredNodeAttrs[attrNameLower];
|
||||
}
|
||||
});
|
||||
return newAttrs;
|
||||
}
|
||||
}
|
||||
|
||||
/** Sort attibutes */
|
||||
function sortAttributes(tree, options, moduleOptions) {
|
||||
const sortType = processModuleOptions(moduleOptions);
|
||||
if (sortType === 'alphabetical') {
|
||||
return sortAttributesInAlphabeticalOrder(tree);
|
||||
}
|
||||
if (sortType === 'frequency') {
|
||||
return sortAttributesByFrequency(tree);
|
||||
}
|
||||
|
||||
// Invalid configuration
|
||||
return tree;
|
||||
}
|
||||
function sortAttributesInAlphabeticalOrder(tree) {
|
||||
tree.walk(node => {
|
||||
if (!node.attrs) {
|
||||
return node;
|
||||
}
|
||||
const newAttrs = {};
|
||||
Object.keys(node.attrs).sort((a, b) => typeof a.localeCompare === 'function' ? a.localeCompare(b) : a - b).forEach(attr => newAttrs[attr] = node.attrs[attr]);
|
||||
node.attrs = newAttrs;
|
||||
return node;
|
||||
});
|
||||
return tree;
|
||||
}
|
||||
function sortAttributesByFrequency(tree) {
|
||||
const tokenchain = new AttributeTokenChain();
|
||||
|
||||
// Traverse through tree to get frequency
|
||||
tree.walk(node => {
|
||||
if (!node.attrs) {
|
||||
return node;
|
||||
}
|
||||
tokenchain.addFromNodeAttrs(node.attrs);
|
||||
return node;
|
||||
});
|
||||
|
||||
// Traverse through tree again, this time sort the attributes
|
||||
tree.walk(node => {
|
||||
if (!node.attrs) {
|
||||
return node;
|
||||
}
|
||||
node.attrs = tokenchain.sortFromNodeAttrs(node.attrs);
|
||||
return node;
|
||||
});
|
||||
return tree;
|
||||
}
|
||||
121
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/sortAttributes.mjs
generated
vendored
Normal file
121
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/sortAttributes.mjs
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
import { sort as timSort } from 'timsort';
|
||||
|
||||
const validOptions = new Set(['frequency', 'alphabetical']);
|
||||
|
||||
const processModuleOptions = options => {
|
||||
if (options === true) return 'alphabetical';
|
||||
|
||||
return validOptions.has(options) ? options : false;
|
||||
};
|
||||
|
||||
class AttributeTokenChain {
|
||||
constructor() {
|
||||
this.freqData = new Map(); // <attr, frequency>[]
|
||||
}
|
||||
|
||||
addFromNodeAttrs(nodeAttrs) {
|
||||
Object.keys(nodeAttrs).forEach(attrName => {
|
||||
const attrNameLower = attrName.toLowerCase();
|
||||
|
||||
if (this.freqData.has(attrNameLower)) {
|
||||
this.freqData.set(attrNameLower, this.freqData.get(attrNameLower) + 1);
|
||||
} else {
|
||||
this.freqData.set(attrNameLower, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
createSortOrder() {
|
||||
let _sortOrder = [...this.freqData.entries()];
|
||||
timSort(_sortOrder, (a, b) => b[1] - a[1]);
|
||||
|
||||
this.sortOrder = _sortOrder.map(i => i[0]);
|
||||
}
|
||||
|
||||
sortFromNodeAttrs(nodeAttrs) {
|
||||
const newAttrs = {};
|
||||
|
||||
// Convert node.attrs attrName into lower case.
|
||||
const loweredNodeAttrs = {};
|
||||
Object.entries(nodeAttrs).forEach(([attrName, attrValue]) => {
|
||||
loweredNodeAttrs[attrName.toLowerCase()] = attrValue;
|
||||
});
|
||||
|
||||
if (!this.sortOrder) {
|
||||
this.createSortOrder();
|
||||
}
|
||||
|
||||
this.sortOrder.forEach(attrNameLower => {
|
||||
// The attrName inside "sortOrder" has been lowered
|
||||
if (loweredNodeAttrs[attrNameLower] != null) {
|
||||
newAttrs[attrNameLower] = loweredNodeAttrs[attrNameLower];
|
||||
}
|
||||
});
|
||||
|
||||
return newAttrs;
|
||||
}
|
||||
}
|
||||
|
||||
/** Sort attibutes */
|
||||
export default function sortAttributes(tree, options, moduleOptions) {
|
||||
const sortType = processModuleOptions(moduleOptions);
|
||||
|
||||
if (sortType === 'alphabetical') {
|
||||
return sortAttributesInAlphabeticalOrder(tree);
|
||||
}
|
||||
|
||||
if (sortType === 'frequency') {
|
||||
return sortAttributesByFrequency(tree);
|
||||
}
|
||||
|
||||
// Invalid configuration
|
||||
return tree;
|
||||
}
|
||||
|
||||
function sortAttributesInAlphabeticalOrder(tree) {
|
||||
tree.walk(node => {
|
||||
if (!node.attrs) {
|
||||
return node;
|
||||
}
|
||||
|
||||
const newAttrs = {};
|
||||
|
||||
Object.keys(node.attrs)
|
||||
.sort((a, b) => typeof a.localeCompare === 'function' ? a.localeCompare(b) : a - b)
|
||||
.forEach(attr => newAttrs[attr] = node.attrs[attr]);
|
||||
|
||||
node.attrs = newAttrs;
|
||||
|
||||
return node;
|
||||
});
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
function sortAttributesByFrequency(tree) {
|
||||
const tokenchain = new AttributeTokenChain();
|
||||
|
||||
// Traverse through tree to get frequency
|
||||
tree.walk(node => {
|
||||
if (!node.attrs) {
|
||||
return node;
|
||||
}
|
||||
|
||||
tokenchain.addFromNodeAttrs(node.attrs);
|
||||
|
||||
return node;
|
||||
});
|
||||
|
||||
// Traverse through tree again, this time sort the attributes
|
||||
tree.walk(node => {
|
||||
if (!node.attrs) {
|
||||
return node;
|
||||
}
|
||||
|
||||
node.attrs = tokenchain.sortFromNodeAttrs(node.attrs);
|
||||
|
||||
return node;
|
||||
});
|
||||
|
||||
return tree;
|
||||
}
|
||||
116
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/sortAttributesWithLists.cjs
generated
vendored
Normal file
116
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/sortAttributesWithLists.cjs
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = collapseAttributeWhitespace;
|
||||
var _timsort = require("timsort");
|
||||
var _collapseAttributeWhitespace = require("./collapseAttributeWhitespace.cjs");
|
||||
// class, rel, ping
|
||||
|
||||
const validOptions = new Set(['frequency', 'alphabetical']);
|
||||
const processModuleOptions = options => {
|
||||
if (options === true) return 'alphabetical';
|
||||
return validOptions.has(options) ? options : false;
|
||||
};
|
||||
class AttributeTokenChain {
|
||||
constructor() {
|
||||
this.freqData = new Map(); // <attrValue, frequency>[]
|
||||
}
|
||||
|
||||
addFromNodeAttrsArray(attrValuesArray) {
|
||||
attrValuesArray.forEach(attrValue => {
|
||||
if (this.freqData.has(attrValue)) {
|
||||
this.freqData.set(attrValue, this.freqData.get(attrValue) + 1);
|
||||
} else {
|
||||
this.freqData.set(attrValue, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
createSortOrder() {
|
||||
let _sortOrder = [...this.freqData.entries()];
|
||||
(0, _timsort.sort)(_sortOrder, (a, b) => b[1] - a[1]);
|
||||
this.sortOrder = _sortOrder.map(i => i[0]);
|
||||
}
|
||||
sortFromNodeAttrsArray(attrValuesArray) {
|
||||
const resultArray = [];
|
||||
if (!this.sortOrder) {
|
||||
this.createSortOrder();
|
||||
}
|
||||
this.sortOrder.forEach(k => {
|
||||
if (attrValuesArray.includes(k)) {
|
||||
resultArray.push(k);
|
||||
}
|
||||
});
|
||||
return resultArray;
|
||||
}
|
||||
}
|
||||
|
||||
/** Sort values inside list-like attributes (e.g. class, rel) */
|
||||
function collapseAttributeWhitespace(tree, options, moduleOptions) {
|
||||
const sortType = processModuleOptions(moduleOptions);
|
||||
if (sortType === 'alphabetical') {
|
||||
return sortAttributesWithListsInAlphabeticalOrder(tree);
|
||||
}
|
||||
if (sortType === 'frequency') {
|
||||
return sortAttributesWithListsByFrequency(tree);
|
||||
}
|
||||
|
||||
// Invalid configuration
|
||||
return tree;
|
||||
}
|
||||
function sortAttributesWithListsInAlphabeticalOrder(tree) {
|
||||
tree.walk(node => {
|
||||
if (!node.attrs) {
|
||||
return node;
|
||||
}
|
||||
Object.keys(node.attrs).forEach(attrName => {
|
||||
const attrNameLower = attrName.toLowerCase();
|
||||
if (!_collapseAttributeWhitespace.attributesWithLists.has(attrNameLower)) {
|
||||
return;
|
||||
}
|
||||
const attrValues = node.attrs[attrName].split(/\s/);
|
||||
node.attrs[attrName] = attrValues.sort((a, b) => {
|
||||
return typeof a.localeCompare === 'function' ? a.localeCompare(b) : a - b;
|
||||
}).join(' ');
|
||||
});
|
||||
return node;
|
||||
});
|
||||
return tree;
|
||||
}
|
||||
function sortAttributesWithListsByFrequency(tree) {
|
||||
const tokenChainObj = {}; // <attrNameLower: AttributeTokenChain>[]
|
||||
|
||||
// Traverse through tree to get frequency
|
||||
tree.walk(node => {
|
||||
if (!node.attrs) {
|
||||
return node;
|
||||
}
|
||||
Object.entries(node.attrs).forEach(([attrName, attrValues]) => {
|
||||
const attrNameLower = attrName.toLowerCase();
|
||||
if (!_collapseAttributeWhitespace.attributesWithLists.has(attrNameLower)) {
|
||||
return;
|
||||
}
|
||||
tokenChainObj[attrNameLower] = tokenChainObj[attrNameLower] || new AttributeTokenChain();
|
||||
tokenChainObj[attrNameLower].addFromNodeAttrsArray(attrValues.split(/\s/));
|
||||
});
|
||||
return node;
|
||||
});
|
||||
|
||||
// Traverse through tree again, this time sort the attribute values
|
||||
tree.walk(node => {
|
||||
if (!node.attrs) {
|
||||
return node;
|
||||
}
|
||||
Object.entries(node.attrs).forEach(([attrName, attrValues]) => {
|
||||
const attrNameLower = attrName.toLowerCase();
|
||||
if (!_collapseAttributeWhitespace.attributesWithLists.has(attrNameLower)) {
|
||||
return;
|
||||
}
|
||||
if (tokenChainObj[attrNameLower]) {
|
||||
node.attrs[attrName] = tokenChainObj[attrNameLower].sortFromNodeAttrsArray(attrValues.split(/\s/)).join(' ');
|
||||
}
|
||||
});
|
||||
return node;
|
||||
});
|
||||
}
|
||||
135
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/sortAttributesWithLists.mjs
generated
vendored
Normal file
135
webGl/my-threejs-test/node_modules/htmlnano/lib/modules/sortAttributesWithLists.mjs
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
// class, rel, ping
|
||||
import { sort as timSort } from 'timsort';
|
||||
import { attributesWithLists } from './collapseAttributeWhitespace.mjs';
|
||||
|
||||
const validOptions = new Set(['frequency', 'alphabetical']);
|
||||
const processModuleOptions = options => {
|
||||
if (options === true) return 'alphabetical';
|
||||
|
||||
return validOptions.has(options) ? options : false;
|
||||
};
|
||||
|
||||
class AttributeTokenChain {
|
||||
constructor() {
|
||||
this.freqData = new Map(); // <attrValue, frequency>[]
|
||||
}
|
||||
|
||||
addFromNodeAttrsArray(attrValuesArray) {
|
||||
attrValuesArray.forEach(attrValue => {
|
||||
if (this.freqData.has(attrValue)) {
|
||||
this.freqData.set(attrValue, this.freqData.get(attrValue) + 1);
|
||||
} else {
|
||||
this.freqData.set(attrValue, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
createSortOrder() {
|
||||
let _sortOrder = [...this.freqData.entries()];
|
||||
timSort(_sortOrder, (a, b) => b[1] - a[1]);
|
||||
|
||||
this.sortOrder = _sortOrder.map(i => i[0]);
|
||||
}
|
||||
|
||||
sortFromNodeAttrsArray(attrValuesArray) {
|
||||
const resultArray = [];
|
||||
|
||||
if (!this.sortOrder) {
|
||||
this.createSortOrder();
|
||||
}
|
||||
|
||||
this.sortOrder.forEach(k => {
|
||||
if (attrValuesArray.includes(k)) {
|
||||
resultArray.push(k);
|
||||
}
|
||||
});
|
||||
|
||||
return resultArray;
|
||||
}
|
||||
}
|
||||
|
||||
/** Sort values inside list-like attributes (e.g. class, rel) */
|
||||
export default function collapseAttributeWhitespace(tree, options, moduleOptions) {
|
||||
const sortType = processModuleOptions(moduleOptions);
|
||||
|
||||
if (sortType === 'alphabetical') {
|
||||
return sortAttributesWithListsInAlphabeticalOrder(tree);
|
||||
}
|
||||
|
||||
if (sortType === 'frequency') {
|
||||
return sortAttributesWithListsByFrequency(tree);
|
||||
}
|
||||
|
||||
// Invalid configuration
|
||||
return tree;
|
||||
}
|
||||
|
||||
function sortAttributesWithListsInAlphabeticalOrder(tree) {
|
||||
tree.walk(node => {
|
||||
if (!node.attrs) {
|
||||
return node;
|
||||
}
|
||||
|
||||
Object.keys(node.attrs).forEach(attrName => {
|
||||
const attrNameLower = attrName.toLowerCase();
|
||||
if (!attributesWithLists.has(attrNameLower)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const attrValues = node.attrs[attrName].split(/\s/);
|
||||
|
||||
node.attrs[attrName] = attrValues.sort((a, b) => {
|
||||
return typeof a.localeCompare === 'function' ? a.localeCompare(b) : a - b;
|
||||
}).join(' ');
|
||||
});
|
||||
|
||||
return node;
|
||||
});
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
function sortAttributesWithListsByFrequency(tree) {
|
||||
const tokenChainObj = {}; // <attrNameLower: AttributeTokenChain>[]
|
||||
|
||||
// Traverse through tree to get frequency
|
||||
tree.walk(node => {
|
||||
if (!node.attrs) {
|
||||
return node;
|
||||
}
|
||||
|
||||
Object.entries(node.attrs).forEach(([attrName, attrValues]) => {
|
||||
const attrNameLower = attrName.toLowerCase();
|
||||
|
||||
if (!attributesWithLists.has(attrNameLower)) {
|
||||
return;
|
||||
}
|
||||
|
||||
tokenChainObj[attrNameLower] = tokenChainObj[attrNameLower] || new AttributeTokenChain();
|
||||
tokenChainObj[attrNameLower].addFromNodeAttrsArray(attrValues.split(/\s/));
|
||||
});
|
||||
|
||||
return node;
|
||||
});
|
||||
|
||||
// Traverse through tree again, this time sort the attribute values
|
||||
tree.walk(node => {
|
||||
if (!node.attrs) {
|
||||
return node;
|
||||
}
|
||||
|
||||
Object.entries(node.attrs).forEach(([attrName, attrValues]) => {
|
||||
const attrNameLower = attrName.toLowerCase();
|
||||
|
||||
if (!attributesWithLists.has(attrNameLower)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tokenChainObj[attrNameLower]) {
|
||||
node.attrs[attrName] = tokenChainObj[attrNameLower].sortFromNodeAttrsArray(attrValues.split(/\s/)).join(' ');
|
||||
}
|
||||
});
|
||||
|
||||
return node;
|
||||
});
|
||||
}
|
||||
18
webGl/my-threejs-test/node_modules/htmlnano/lib/presets/ampSafe.cjs
generated
vendored
Normal file
18
webGl/my-threejs-test/node_modules/htmlnano/lib/presets/ampSafe.cjs
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _safe = _interopRequireDefault(require("./safe.cjs"));
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
/**
|
||||
* A safe preset for AMP pages (https://www.ampproject.org)
|
||||
*/
|
||||
var _default = exports.default = {
|
||||
..._safe.default,
|
||||
collapseBooleanAttributes: {
|
||||
amphtml: true
|
||||
},
|
||||
minifyJs: false
|
||||
};
|
||||
11
webGl/my-threejs-test/node_modules/htmlnano/lib/presets/ampSafe.mjs
generated
vendored
Normal file
11
webGl/my-threejs-test/node_modules/htmlnano/lib/presets/ampSafe.mjs
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import safePreset from './safe.mjs';
|
||||
|
||||
/**
|
||||
* A safe preset for AMP pages (https://www.ampproject.org)
|
||||
*/
|
||||
export default { ...safePreset,
|
||||
collapseBooleanAttributes: {
|
||||
amphtml: true,
|
||||
},
|
||||
minifyJs: false,
|
||||
};
|
||||
27
webGl/my-threejs-test/node_modules/htmlnano/lib/presets/max.cjs
generated
vendored
Normal file
27
webGl/my-threejs-test/node_modules/htmlnano/lib/presets/max.cjs
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _safe = _interopRequireDefault(require("./safe.cjs"));
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
/**
|
||||
* Maximal minification (might break some pages)
|
||||
*/
|
||||
var _default = exports.default = {
|
||||
..._safe.default,
|
||||
collapseWhitespace: 'all',
|
||||
removeComments: 'all',
|
||||
removeAttributeQuotes: true,
|
||||
removeRedundantAttributes: true,
|
||||
mergeScripts: true,
|
||||
mergeStyles: true,
|
||||
removeUnusedCss: {},
|
||||
minifyCss: {
|
||||
preset: 'default'
|
||||
},
|
||||
minifySvg: {},
|
||||
minifyConditionalComments: true,
|
||||
removeOptionalTags: true
|
||||
};
|
||||
20
webGl/my-threejs-test/node_modules/htmlnano/lib/presets/max.mjs
generated
vendored
Normal file
20
webGl/my-threejs-test/node_modules/htmlnano/lib/presets/max.mjs
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import safePreset from './safe.mjs';
|
||||
|
||||
/**
|
||||
* Maximal minification (might break some pages)
|
||||
*/
|
||||
export default { ...safePreset,
|
||||
collapseWhitespace: 'all',
|
||||
removeComments: 'all',
|
||||
removeAttributeQuotes: true,
|
||||
removeRedundantAttributes: true,
|
||||
mergeScripts: true,
|
||||
mergeStyles: true,
|
||||
removeUnusedCss: {},
|
||||
minifyCss: {
|
||||
preset: 'default',
|
||||
},
|
||||
minifySvg: {},
|
||||
minifyConditionalComments: true,
|
||||
removeOptionalTags: true,
|
||||
};
|
||||
65
webGl/my-threejs-test/node_modules/htmlnano/lib/presets/safe.cjs
generated
vendored
Normal file
65
webGl/my-threejs-test/node_modules/htmlnano/lib/presets/safe.cjs
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
/**
|
||||
* Minify HTML in a safe way without breaking anything.
|
||||
*/
|
||||
var _default = exports.default = {
|
||||
/* ----------------------------------------
|
||||
* Attributes
|
||||
* ---------------------------------------- */
|
||||
// normalize the case of attribute names and values
|
||||
// normalizeAttributeValues will also normalize property value with invalid value default
|
||||
// See https://html.spec.whatwg.org/#invalid-value-default
|
||||
normalizeAttributeValues: true,
|
||||
removeEmptyAttributes: true,
|
||||
collapseAttributeWhitespace: true,
|
||||
// removeRedundantAttributes will remove attributes when missing value default matches the attribute's value
|
||||
// See https://html.spec.whatwg.org/#missing-value-default
|
||||
removeRedundantAttributes: false,
|
||||
// collapseBooleanAttributes will also collapse those default state can be omitted
|
||||
collapseBooleanAttributes: {
|
||||
amphtml: false
|
||||
},
|
||||
deduplicateAttributeValues: true,
|
||||
minifyUrls: false,
|
||||
sortAttributes: false,
|
||||
sortAttributesWithLists: 'alphabetical',
|
||||
/* ----------------------------------------
|
||||
* Minify HTML content
|
||||
* ---------------------------------------- */
|
||||
collapseWhitespace: 'conservative',
|
||||
removeComments: 'safe',
|
||||
minifyConditionalComments: false,
|
||||
removeOptionalTags: false,
|
||||
removeAttributeQuotes: false,
|
||||
/* ----------------------------------------
|
||||
* Minify inline <style>, <script> and <svg> tag
|
||||
* ---------------------------------------- */
|
||||
mergeStyles: false,
|
||||
mergeScripts: false,
|
||||
minifyCss: {
|
||||
preset: 'default'
|
||||
},
|
||||
minifyJs: {},
|
||||
minifyJson: {},
|
||||
minifySvg: {
|
||||
plugins: [{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {
|
||||
collapseGroups: false,
|
||||
convertShapeToPath: false
|
||||
}
|
||||
}
|
||||
}]
|
||||
},
|
||||
removeUnusedCss: false,
|
||||
/* ----------------------------------------
|
||||
* Miscellaneous
|
||||
* ---------------------------------------- */
|
||||
custom: []
|
||||
};
|
||||
65
webGl/my-threejs-test/node_modules/htmlnano/lib/presets/safe.mjs
generated
vendored
Normal file
65
webGl/my-threejs-test/node_modules/htmlnano/lib/presets/safe.mjs
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Minify HTML in a safe way without breaking anything.
|
||||
*/
|
||||
export default {
|
||||
/* ----------------------------------------
|
||||
* Attributes
|
||||
* ---------------------------------------- */
|
||||
// normalize the case of attribute names and values
|
||||
// normalizeAttributeValues will also normalize property value with invalid value default
|
||||
// See https://html.spec.whatwg.org/#invalid-value-default
|
||||
normalizeAttributeValues: true,
|
||||
removeEmptyAttributes: true,
|
||||
collapseAttributeWhitespace: true,
|
||||
// removeRedundantAttributes will remove attributes when missing value default matches the attribute's value
|
||||
// See https://html.spec.whatwg.org/#missing-value-default
|
||||
removeRedundantAttributes: false,
|
||||
// collapseBooleanAttributes will also collapse those default state can be omitted
|
||||
collapseBooleanAttributes: {
|
||||
amphtml: false,
|
||||
},
|
||||
deduplicateAttributeValues: true,
|
||||
|
||||
minifyUrls: false,
|
||||
|
||||
sortAttributes: false,
|
||||
sortAttributesWithLists: 'alphabetical',
|
||||
|
||||
/* ----------------------------------------
|
||||
* Minify HTML content
|
||||
* ---------------------------------------- */
|
||||
collapseWhitespace: 'conservative',
|
||||
removeComments: 'safe',
|
||||
minifyConditionalComments: false,
|
||||
removeOptionalTags: false,
|
||||
removeAttributeQuotes: false,
|
||||
/* ----------------------------------------
|
||||
* Minify inline <style>, <script> and <svg> tag
|
||||
* ---------------------------------------- */
|
||||
mergeStyles: false,
|
||||
mergeScripts: false,
|
||||
minifyCss: {
|
||||
preset: 'default',
|
||||
},
|
||||
minifyJs: {},
|
||||
minifyJson: {},
|
||||
minifySvg: {
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {
|
||||
collapseGroups: false,
|
||||
convertShapeToPath: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
removeUnusedCss: false,
|
||||
|
||||
/* ----------------------------------------
|
||||
* Miscellaneous
|
||||
* ---------------------------------------- */
|
||||
custom: []
|
||||
};
|
||||
132
webGl/my-threejs-test/node_modules/htmlnano/package.json
generated
vendored
Normal file
132
webGl/my-threejs-test/node_modules/htmlnano/package.json
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
{
|
||||
"name": "htmlnano",
|
||||
"version": "2.1.0",
|
||||
"description": "Modular HTML minifier, built on top of the PostHTML",
|
||||
"main": "index.cjs",
|
||||
"module": "index.mjs",
|
||||
"source": "index.mjs",
|
||||
"exports": {
|
||||
".": {
|
||||
"require": "./index.cjs",
|
||||
"import": "./index.mjs"
|
||||
},
|
||||
"./index.mjs": {
|
||||
"import": "./index.mjs"
|
||||
},
|
||||
"./index.cjs": {
|
||||
"require": "./index.cjs"
|
||||
}
|
||||
},
|
||||
"types": "index.d.ts",
|
||||
"author": "Kirill Maltsev <maltsevkirill@gmail.com>",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"clean": "rimraf lib/*.cjs lib/**/*.cjs",
|
||||
"compile": "npm run clean && babel -d lib/ lib/ --out-file-extension .cjs",
|
||||
"lint": "eslint --fix *.mjs lib/*.mjs lib/**/*.mjs test/*.mjs test/**/*.mjs",
|
||||
"pretest": "npm run lint && npm run compile",
|
||||
"test": ":",
|
||||
"posttest": "mocha --timeout 5000 --require @babel/register --recursive --check-leaks --globals addresses",
|
||||
"prepare": "npm run compile"
|
||||
},
|
||||
"keywords": [
|
||||
"posthtml",
|
||||
"posthtml-plugin",
|
||||
"html",
|
||||
"postproccessor",
|
||||
"minifier"
|
||||
],
|
||||
"babel": {
|
||||
"presets": [
|
||||
[
|
||||
"@babel/env",
|
||||
{
|
||||
"targets": {
|
||||
"node": 10
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
"plugins": [
|
||||
[
|
||||
"@aminya/babel-plugin-replace-import-extension",
|
||||
{
|
||||
"extMapping": {
|
||||
".mjs": ".cjs"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"cosmiconfig": "^8.0.0",
|
||||
"posthtml": "^0.16.5",
|
||||
"timsort": "^0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.15.7",
|
||||
"@babel/core": "^7.15.5",
|
||||
"@babel/eslint-parser": "^7.17.0",
|
||||
"@babel/preset-env": "^7.15.6",
|
||||
"@babel/register": "^7.15.3",
|
||||
"@aminya/babel-plugin-replace-import-extension": "1.2.0",
|
||||
"cssnano": "^6.0.0",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint-plugin-import": "^2.28.1",
|
||||
"eslint-plugin-path-import-extension": "^0.9.0",
|
||||
"expect": "^29.0.0",
|
||||
"mocha": "^10.1.0",
|
||||
"postcss": "^8.3.11",
|
||||
"purgecss": "^5.0.0",
|
||||
"relateurl": "^0.2.7",
|
||||
"rimraf": "^5.0.0",
|
||||
"srcset": "4.0.0",
|
||||
"svgo": "^3.0.2",
|
||||
"terser": "^5.21.0",
|
||||
"uncss": "^0.17.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"cssnano": "^6.0.0",
|
||||
"postcss": "^8.3.11",
|
||||
"purgecss": "^5.0.0",
|
||||
"relateurl": "^0.2.7",
|
||||
"srcset": "4.0.0",
|
||||
"svgo": "^3.0.2",
|
||||
"terser": "^5.10.0",
|
||||
"uncss": "^0.17.3"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"cssnano": {
|
||||
"optional": true
|
||||
},
|
||||
"postcss": {
|
||||
"optional": true
|
||||
},
|
||||
"purgecss": {
|
||||
"optional": true
|
||||
},
|
||||
"relateurl": {
|
||||
"optional": true
|
||||
},
|
||||
"srcset": {
|
||||
"optional": true
|
||||
},
|
||||
"svgo": {
|
||||
"optional": true
|
||||
},
|
||||
"terser": {
|
||||
"optional": true
|
||||
},
|
||||
"uncss": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/posthtml/htmlnano.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/posthtml/htmlnano/issues"
|
||||
},
|
||||
"homepage": "https://github.com/posthtml/htmlnano"
|
||||
}
|
||||
48
webGl/my-threejs-test/node_modules/htmlnano/test.js
generated
vendored
Normal file
48
webGl/my-threejs-test/node_modules/htmlnano/test.js
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
const htmlnano = require('.');
|
||||
// const posthtml = require('posthtml');
|
||||
const safePreset = require('./lib/presets/safe');
|
||||
// const options = {
|
||||
// minifySvg: false,
|
||||
// minifyJs: false,
|
||||
// };
|
||||
// // posthtml, posthtml-render, and posthtml-parse options
|
||||
// const postHtmlOptions = {
|
||||
// sync: true, // https://github.com/posthtml/posthtml#usage
|
||||
// lowerCaseTags: true, // https://github.com/posthtml/posthtml-parser#options
|
||||
// quoteAllAttributes: false, // https://github.com/posthtml/posthtml-render#options
|
||||
// };
|
||||
|
||||
// const html = `
|
||||
// <!doctype html>
|
||||
// <html lang="en">
|
||||
// <head>
|
||||
// <meta charset="utf-8">
|
||||
// <title></title>
|
||||
// <script class="fob">alert(1)</script>
|
||||
// <script>alert(2)</script>
|
||||
// </head>
|
||||
// <body>
|
||||
// <script>alert(3)</script>
|
||||
// <script>alert(4)</script>
|
||||
// </body>
|
||||
// </html>
|
||||
// `;
|
||||
|
||||
const options = {
|
||||
minifySvg: safePreset.minifySvg,
|
||||
};
|
||||
const html = `
|
||||
<input type="text" class="form-control" name="testInput" autofocus="" autocomplete="off" id="testId"><a id="testId" href="#" class="testClass"></a><img width="20" src="../images/image.png" height="40" alt="image" class="cls" id="id2">
|
||||
`;
|
||||
|
||||
htmlnano
|
||||
// "preset" arg might be skipped (see "Presets" section below for more info)
|
||||
// "postHtmlOptions" arg might be skipped
|
||||
.process(html)
|
||||
.then(function (result) {
|
||||
// result.html is minified
|
||||
console.log(result.html);
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
Reference in New Issue
Block a user