Skip to content

Commit

Permalink
New --skip flag to selectively disable hashing
Browse files Browse the repository at this point in the history
  • Loading branch information
dpilafian committed Jul 14, 2024
1 parent 95ae3eb commit 8cb7998
Show file tree
Hide file tree
Showing 22 changed files with 176 additions and 77 deletions.
27 changes: 15 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,16 @@ You can also install **rev-web-assets** globally (`--global`) and then run it an

### 3. CLI flags
Command-line flags:
| Flag | Description | Value |
| --------------------- | ------------------------------------------------------- | ---------- |
| `--cd` | Change working directory before starting starting. | **string** |
| `--force` | Revision (hash) all asset files even if not referenced. | N/A |
| `--manifest` | Output the list of files to: **manifest.json** | N/A |
| `--meta-content-base` | Make meta URLs, like "og:image", absolute. | **string** |
| `--note` | Place to add a comment only for humans. | **string** |
| `--quiet` | Suppress informational messages. | N/A |
| `--summary` | Only print out the single line summary message. | N/A |
| Flag | Description | Value |
| --------------------- | ---------------------------------------------------------------------- | ---------- |
| `--cd` | Change working directory before starting starting. | **string** |
| `--force` | Revision (hash) all asset files even if not referenced. | N/A |
| `--manifest` | Output the list of files to: **manifest.json** | N/A |
| `--meta-content-base` | Make meta URLs, like "og:image", absolute. | **string** |
| `--note` | Place to add a comment only for humans. | **string** |
| `--quiet` | Suppress informational messages. | N/A |
| `--skip` | Do not revision (hash) asset files with paths containing given string. | **string** |
| `--summary` | Only print out the single line summary message. | N/A |

Examples:
- `rev-web-assets web/source web/target`<br>
Expand All @@ -73,7 +74,8 @@ Examples:
- `rev-web-assets source target --meta-content-base=https://example.net`<br>
Prepends the base to `<meta>` URLs.

_**Note:** Single quotes in commands are normalized so they work cross-platform and avoid the errors often encountered on Microsoft Windows._
_**Note:** Single quotes in commands are normalized so they work cross-platform and avoid the
errors often encountered on Microsoft Windows._

URLs in `<meta>` tag `content` attributes generally need to be absolute URLs.&nbsp;
Setting the `--meta-content-base` flag to `https://example.net` will transform the line of HTML from:
Expand All @@ -92,15 +94,16 @@ export type ManifestDetail = {
filename: string, //source filename of asset file
canonical: string, //normalized path used to lookup asset in manifest
canonicalFolder: string, //directory of the normalized path of the asset file
isHtml: boolean, //true if the asset file is HTML
isCss: boolean, //true if the asset file is CSS
isHtml: boolean, //asset file is HTML
isCss: boolean, //asset file is CSS
bytes: number | null, //asset file size
hash: string | null, //eight-digit cache busting hex humber that changes if the asset changes
hashedFilename: string | null, //filename of the asset with hash inserted before the file extension
destFolder: string, //directory of the target asset
destPath: string | null, //folder and filename of the target asset
usedIn: string[] | null, //files that references the asset
references: number | null, //number of times the asset is referenced
skipped: boolean, //asset file is configured to not be hashed
};
```
Example:
Expand Down
10 changes: 6 additions & 4 deletions bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ import { cliArgvUtil } from 'cli-argv-util';
import { revWebAssets } from '../dist/rev-web-assets.js';

// Parameters and flags
const validFlags = ['cd', 'force', 'manifest', 'meta-content-base', 'note', 'quiet', 'summary'];
const cli = cliArgvUtil.parse(validFlags);
const source = cli.params[0];
const target = cli.params[1];
const validFlags =
['cd', 'force', 'manifest', 'meta-content-base', 'note', 'quiet', 'skip', 'summary'];
const cli = cliArgvUtil.parse(validFlags);
const source = cli.params[0];
const target = cli.params[1];

// Revision Web Assets
const error =
Expand All @@ -43,6 +44,7 @@ const options = {
force: cli.flagOn.force,
metaContentBase: cli.flagMap.metaContentBase ?? null,
saveManifest: cli.flagOn.manifest,
skip: cli.flagMap.skip ?? null,
};
const results = revWebAssets.revision(source, target, options);
if (!cli.flagOn.quiet)
Expand Down
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,19 +79,19 @@
"slash": "~5.1"
},
"devDependencies": {
"@eslint/js": "~9.3",
"@eslint/js": "~9.7",
"@types/fancy-log": "~2.0",
"@types/node": "~20.12",
"@types/node": "~20.14",
"add-dist-header": "~1.4",
"assert-deep-strict-equal": "~1.2",
"copy-file-util": "~1.2",
"eslint": "8.57.0",
"jshint": "~2.13",
"mocha": "~10.4",
"rimraf": "~5.0",
"mocha": "~10.6",
"rimraf": "~6.0",
"run-scripts-util": "~1.2",
"typescript": "~5.4",
"typescript-eslint": "~7.11",
"typescript": "~5.5",
"typescript-eslint": "~7.16",
"w3c-html-validator": "~1.8"
}
}
26 changes: 16 additions & 10 deletions rev-web-assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,23 @@ export type Settings = {
force: boolean, //revision (hash) all asset files even if not referenced
metaContentBase: string | null, //make meta URLs, like "og:image", absolute
saveManifest: boolean, //output the list of files to manifest.json in the target folder
skip: string | null, //do not revision (hash) asset files with paths containing given string.
};
export type ManifestDetail = {
origin: string, //source path of asset file
filename: string, //source filename of asset file
canonical: string, //normalized path used to lookup asset in manifest
canonicalFolder: string, //directory of the normalized path of the asset file
isHtml: boolean, //true if the asset file is HTML
isCss: boolean, //true if the asset file is CSS
isHtml: boolean, //asset file is HTML
isCss: boolean, //asset file is CSS
bytes: number | null, //asset file size
hash: string | null, //eight-digit cache busting hex humber that changes if the asset changes
hashedFilename: string | null, //filename of the asset with hash inserted before the file extension
destFolder: string, //directory of the target asset
destPath: string | null, //folder and filename of the target asset
usedIn: string[] | null, //files that references the asset
references: number | null, //number of times the asset is referenced
skipped: boolean, //asset file is configured to not be hashed
};
export type Manifest = ManifestDetail[]; //list of assets
export type Results = {
Expand All @@ -44,7 +46,7 @@ export type ReporterSettings = {

const revWebAssets = {

manifest(source: string, target: string): ManifestDetail[] {
manifest(source: string, target: string, skip: string | null): ManifestDetail[] {
// Creates a manifest list with stub manifest details for each file in the source folder.
const files = fs.readdirSync(source, { recursive: true })
.map(file => slash(path.join(source, file.toString())))
Expand All @@ -71,6 +73,7 @@ const revWebAssets = {
destPath: null,
usedIn: isHtml ? null : [],
references: isHtml ? null : 0,
skipped: !isHtml && !!skip && file.includes(skip),
};
}
const manifest = files.map(process);
Expand All @@ -84,7 +87,7 @@ const revWebAssets = {
return slash(path.normalize(!hash ? filename : filename.replace(lastDot, '.' + hash + '.')));
},

removeHash(filename: string): string {
stripHash(filename: string): string {
// Reverts a hashed filename back to its original filename (for use in specification cases
// to verify hashed file exists).
// Example:
Expand All @@ -110,15 +113,17 @@ const revWebAssets = {
// the hashed filename.
// Example function output:
// '<img src=logo.c2f3e84e.png alt=Logo>'
const webPages = ['.html', '.htm', '.php'];
const replacer = (matched: string, pre: string, uri: string, post: string): string => {
// Example matched broken into 3 parts:
// '<img src=logo.png alt=Logo>' ==> '<img src=', 'logo.png', ' alt=Logo>'
const ext = path.extname(uri);
const doNotHash = uri.includes(':') || ['.html', '.htm', '.php'].includes(ext) || ext.length < 2;
const doNotHash = uri.includes(':') || webPages.includes(ext) || ext.length < 2;
const canonicalPath = detail.canonicalFolder ? detail.canonicalFolder + '/' : '';
const canonical = slash(path.normalize(canonicalPath + uri));
const assetDetail = doNotHash ? null : manifest.find(detail => detail.canonical === canonical);
if (assetDetail && !assetDetail.hash)
const skipAsset = !!settings.skip && uri.includes(settings.skip);
if (assetDetail && !assetDetail.hash && !skipAsset)
revWebAssets.calcAssetHash(assetDetail);
if (assetDetail)
assetDetail.references!++;
Expand Down Expand Up @@ -186,8 +191,9 @@ const revWebAssets = {
force: false,
metaContentBase: null,
saveManifest: false,
skip: null,
};
const settings = { ...defaults, ...options };
const settings = { ...defaults, ...options };
const startTime = Date.now();
const normalize = (folder: string) =>
!folder ? '' : slash(path.normalize(folder)).replace(/\/$/, '');
Expand All @@ -206,11 +212,11 @@ const revWebAssets = {
null;
if (errorMessage)
throw Error('[rev-web-assets] ' + errorMessage);
const manifest = revWebAssets.manifest(source, target);
const manifest = revWebAssets.manifest(source, target, settings.skip);
revWebAssets.processHtml(manifest, settings);
revWebAssets.processCss(manifest, settings);
const hashUnusedAsset = (detail: ManifestDetail) =>
!detail.hash && !detail.isHtml && revWebAssets.calcAssetHash(detail);
!detail.hash && !detail.isHtml && !detail.skipped && revWebAssets.calcAssetHash(detail);
if (settings.force)
manifest.forEach(hashUnusedAsset);
revWebAssets.copyAssets(manifest);
Expand All @@ -231,7 +237,7 @@ const revWebAssets = {
const defaults = {
summaryOnly: false,
};
const settings = { ...defaults, ...options };
const settings = { ...defaults, ...options };
const name = chalk.gray('rev-web-assets');
const source = chalk.blue.bold(results.source);
const target = chalk.magenta(results.target);
Expand Down
Binary file added spec/fixtures/source/graphics/do-not-hash.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions spec/fixtures/source/mock1.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,16 @@ <h3>Cheese</h3>
<article>
<h3>Images</h3>
<figure>
<img src=graphics/do-not-hash.jpg alt=neon>
<img src=graphics/mock1.jpg alt=neon>
<img src=subfolder/graphics/mock2.jpg alt=neon>
</figure>
<p>Cover 1A</p>
<p>Cover 1B</p>
<p>Cover 1C</p>
<p>Cover 2A</p>
<p>Cover 2B</p>
<p>Cover 2C</p>
</article>
<footer>
<a href=https://github.com/center-key/rev-web-assets>github.com/center-key/rev-web-assets</a>
Expand Down
5 changes: 4 additions & 1 deletion spec/fixtures/source/mock1.min.css
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ article >p {
padding: 30px;
}
article >p:nth-of-type(1) {
background-image: url(graphics/mock1.jpg);
background-image: url(graphics/do-not-hash.jpg);
}
article >p:nth-of-type(2) {
background-image: url(graphics/mock1.jpg);
}
article >p:nth-of-type(3) {
background-image: url(subfolder/graphics/mock2.jpg);
}
1 change: 1 addition & 0 deletions spec/fixtures/source/mock1.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<article>
<h3>Images</h3>
<figure>
<img src=graphics/do-not-hash.jpg alt=neon>
<img src=graphics/mock1.jpg alt=neon>
<img src=subfolder/graphics/mock2.jpg alt=neon>
</figure>
Expand Down
3 changes: 3 additions & 0 deletions spec/fixtures/source/subfolder/mock2.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,16 @@ <h3>Cheese</h3>
<article>
<h3>Images</h3>
<figure>
<img src=../graphics/do-not-hash.jpg alt=neon>
<img src=../graphics/mock1.jpg alt=neon>
<img src=./graphics/../graphics////mock2.jpg alt=neon>
</figure>
<p>Cover 1A</p>
<p>Cover 1B</p>
<p>Cover 1C</p>
<p>Cover 2A</p>
<p>Cover 2B</p>
<p>Cover 2C</p>
</article>
<footer>
<a href=https://github.com/center-key/rev-web-assets>github.com/center-key/rev-web-assets</a>
Expand Down
7 changes: 5 additions & 2 deletions spec/fixtures/source/subfolder/mock2.min.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
section#two.hide-bad >figure.bad {
display: none;
}
article >p:nth-of-type(3) {
article >p:nth-of-type(4) {
background-image: url(../graphics/do-not-hash.jpg);
}
article >p:nth-of-type(5) {
background-image: url(../graphics/mock1.jpg);
}
article >p:nth-of-type(4) {
article >p:nth-of-type(6) {
background-image: url(graphics/mock2.jpg);
}
3 changes: 3 additions & 0 deletions spec/fixtures/source/subfolder/mock2.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,16 @@
<article>
<h3>Images</h3>
<figure>
<img src=../graphics/do-not-hash.jpg alt=neon>
<img src=../graphics/mock1.jpg alt=neon>
<img src=./graphics/../graphics////mock2.jpg alt=neon>
</figure>
<p>Cover 1A</p>
<p>Cover 1B</p>
<p>Cover 1C</p>
<p>Cover 2A</p>
<p>Cover 2B</p>
<p>Cover 2C</p>
</article>
<footer>
<a href=https://github.com/center-key/rev-web-assets>github.com/center-key/rev-web-assets</a>
Expand Down
Binary file added spec/fixtures/target-force/do-not-hash.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 20 additions & 2 deletions spec/fixtures/target-force/manifest.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
[
{
"origin": "spec/fixtures/source/graphics/do-not-hash.jpg",
"filename": "do-not-hash.jpg",
"canonicalFolder": "",
"canonical": "do-not-hash.jpg",
"bytes": null,
"isHtml": false,
"isCss": false,
"hash": null,
"hashedFilename": null,
"destFolder": "spec/fixtures/target-force",
"destPath": "spec/fixtures/target-force/do-not-hash.jpg",
"usedIn": [],
"references": 0,
"skipped": true
},
{
"origin": "spec/fixtures/source/graphics/mock1.jpg",
"filename": "mock1.jpg",
Expand All @@ -12,7 +28,8 @@
"destFolder": "spec/fixtures/target-force",
"destPath": "spec/fixtures/target-force/mock1.ad41b203.jpg",
"usedIn": [],
"references": 0
"references": 0,
"skipped": false
},
{
"origin": "spec/fixtures/source/graphics/unused.jpg",
Expand All @@ -27,6 +44,7 @@
"destFolder": "spec/fixtures/target-force",
"destPath": "spec/fixtures/target-force/unused.eb19dd7e.jpg",
"usedIn": [],
"references": 0
"references": 0,
"skipped": false
}
]
Binary file added spec/fixtures/target/graphics/do-not-hash.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 8cb7998

Please sign in to comment.