1
0
mirror of https://github.com/locomotivemtl/locomotive-boilerplate.git synced 2026-01-15 00:55:08 +08:00

Merge branch 'master' into feature/css-variables

This commit is contained in:
Deven Caron
2023-02-09 09:01:24 -05:00
10 changed files with 1643 additions and 1559 deletions

View File

@@ -24,7 +24,7 @@ Learn more about [languages and technologies](docs/technologies.md).
Make sure you have the following installed:
* [Node] — at least 14.17, the latest LTS is recommended.
* [NPM] — at least 6.0, the latest LTS is recommended.
* [NPM] — at least 8.0, the latest LTS is recommended.
> 💡 You can use [NVM] to install and use different versions of Node via the command-line.

View File

@@ -1,3 +1,3 @@
{
"version": 1667240825414
"version": 1673639671975
}

View File

@@ -14,10 +14,9 @@
html {
min-height: 100%; // [2]
line-height: $line-height;
line-height: $line-height; // [3]
font-family: ff("sans");
color: $font-color;
line-height: $line-height; // [3]
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;

View File

@@ -28,7 +28,7 @@ $font-fallback-mono: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console
// <font-id>: (<font-name>, <font-fallbacks>)
// ```
$font-families: (
sans: join(Source Sans, $font-fallback-sans, $separator: comma),
sans: join("Source Sans", $font-fallback-sans, $separator: comma),
);
// List of custom font faces as tuples.
@@ -37,10 +37,10 @@ $font-families: (
// <font-name> <font-file-basename> <font-weight> <font-style>
// ```
$font-faces: (
(Source Sans, "SourceSans3-Bold", 700, normal),
(Source Sans, "SourceSans3-BoldIt", 700, italic),
(Source Sans, "SourceSans3-Regular", 400, normal),
(Source Sans, "SourceSans3-RegularIt", 400, italic),
("Source Sans", "SourceSans3-Bold", 700, normal),
("Source Sans", "SourceSans3-BoldIt", 700, italic),
("Source Sans", "SourceSans3-Regular", 400, normal),
("Source Sans", "SourceSans3-RegularIt", 400, italic),
);
// Typography

View File

@@ -2,8 +2,15 @@ import loconfig from '../utils/config.js';
import message from '../utils/message.js';
import resolve from '../utils/template.js';
import { randomBytes } from 'node:crypto';
import events from 'node:events';
import {
createReadStream,
createWriteStream,
} from 'node:fs';
import {
mkdir,
rename,
rm,
readFile,
writeFile,
} from 'node:fs/promises';
@@ -11,14 +18,41 @@ import {
basename,
dirname,
} from 'node:path';
import readline from 'node:readline';
/**
* @typedef {object} VersionOptions
* @property {string|number|null} prettyPrint - A string or number to insert
* white space into the output JSON string for readability purposes.
* @property {string} versionFormat - The version number format.
* @property {string} versionKey - The JSON field name assign
* the version number to.
* @property {string|RegExp} versionKey - Either:
* - A string representing the JSON field name assign the version number to.
*
* Explicit:
*
* ```json
* "key": "json:version"
* ```
*
* Implicit:
*
* ```json
* "key": "version"
* ```
*
* - A `RegExp` object or regular expression string prefixed with `regexp:`.
*
* ```json
* "key": "regexp:(?<=^const ASSETS_VERSION = ')(?<version>\\d+)(?=';$)"
* ```
*
* ```js
* key: new RegExp('(?<=^const ASSETS_VERSION = ')(?<version>\\d+)(?=';$)')
* ```
*
* ```js
* key: /(?<=^const ASSETS_VERSION = ')(?<version>\d+)(?=';$)/
* ```
*/
/**
@@ -93,7 +127,7 @@ export default async function bumpVersions(versionOptions = null) {
* @return {string|number}
*/
function createVersionNumber(format) {
let [ type, modifier ] = format.split(':');
let [ type, modifier ] = format.split(':', 2);
switch (type) {
case 'hex':
@@ -106,6 +140,9 @@ function createVersionNumber(format) {
return randomBytes(modifier).toString('hex');
case 'regex':
return new RegExp(modifier);
case 'timestamp':
return Date.now().valueOf();
}
@@ -127,24 +164,14 @@ async function handleBumpVersion(outfile, label, options) {
console.time(timeLabel);
try {
outfile = resolve(outfile);
options.key = parseVersionKey(options.key);
let json;
try {
json = JSON.parse(await readFile(outfile));
} catch (err) {
json = {};
message(`${label} is a new file`, 'notice');
await mkdir(dirname(outfile), { recursive: true });
if (options.key instanceof RegExp) {
await handleBumpVersionWithRegExp(outfile, label, options);
} else {
await handleBumpVersionInJson(outfile, label, options);
}
json[options.key] = createVersionNumber(options.format);
await writeFile(outfile, JSON.stringify(json, null, options.pretty));
message(`${label} bumped`, 'success', timeLabel);
} catch (err) {
message(`Error bumping ${label}`, 'error');
@@ -156,3 +183,133 @@ async function handleBumpVersion(outfile, label, options) {
});
}
}
/**
* Changes the version number for the provided JSON key in file.
*
* @async
* @param {string} outfile
* @param {string} label
* @param {object} options
* @param {string} options.key
* @return {Promise}
*/
async function handleBumpVersionInJson(outfile, label, options) {
outfile = resolve(outfile);
let json;
try {
json = JSON.parse(await readFile(outfile, { encoding: 'utf8' }));
} catch (err) {
json = {};
message(`${label} is a new file`, 'notice');
await mkdir(dirname(outfile), { recursive: true });
}
const version = createVersionNumber(options.format);
json[options.key] = version;
return await writeFile(
outfile,
JSON.stringify(json, null, options.pretty),
{ encoding: 'utf8' }
);
}
/**
* Changes the version number for the provided RegExp in file.
*
* @async
* @param {string} outfile
* @param {string} label
* @param {object} options
* @param {RegExp} options.key
* @return {Promise}
*/
async function handleBumpVersionWithRegExp(outfile, label, options) {
outfile = resolve(outfile);
const bckfile = `${outfile}~`;
await rename(outfile, bckfile);
try {
const rl = readline.createInterface({
input: createReadStream(bckfile),
});
const version = createVersionNumber(options.format);
const writeStream = createWriteStream(outfile, { encoding: 'utf8' });
rl.on('line', (line) => {
const found = line.match(options.key);
if (found) {
const groups = (found.groups ?? {});
const replace = found[0].replace(
(groups.build ?? groups.version ?? found[1] ?? found[0]),
version
);
line = line.replace(found[0], replace);
}
writeStream.write(line + "\n");
});
await events.once(rl, 'close');
await rm(bckfile);
} catch (err) {
await rm(outfile, { force: true });
await rename(bckfile, outfile);
throw err;
}
}
/**
* Parses the version key.
*
* @param {*} key - The version key.
* @return {string|RegExp}
*/
function parseVersionKey(key) {
if (key instanceof RegExp) {
return key;
}
if (typeof key !== 'string') {
throw new TypeError(
'Expected \'key\' to be either a string or a RegExp'
);
}
const delimiter = key.indexOf(':');
if (delimiter === -1) {
// Assumes its a JSON key
return key;
}
const type = key.slice(0, delimiter);
const value = key.slice(delimiter + 1);
switch (type) {
case 'json':
return value;
case 'regex':
case 'regexp':
return new RegExp(value);
}
throw new TypeError(
'Expected \'key\' type to be either "json" or "regexp"'
);
}

View File

@@ -15,6 +15,7 @@
* [`scripts`](#scripts)
* [`styles`](#styles)
* [`svgs`](#svgs)
* [`versions`](#versions)
---
@@ -28,7 +29,9 @@ Learn more about the boilerplate's [tasks](#tasks) below.
Make sure you have the following installed:
* [Node] — at least 14.17, the latest LTS is recommended.
* [NPM] — at least 6.0, the latest LTS is recommended.
* [NPM] — at least 8.0, the latest LTS is recommended.
> 💡 You can use [NVM] to install and use different versions of Node via the command-line.
```sh
# Switch to recommended Node version from .nvmrc
@@ -262,8 +265,8 @@ See [`scripts.js`](../build/tasks/scripts.js) for details.
### `styles`
A wrapper around [node-sass] (and optionally [Autoprefixer] via [PostCSS])
for compiling and minifying Sass into CSS.
A wrapper around [node-sass] (with optional support for [Autoprefixer]
via [PostCSS]) for compiling and minifying Sass into CSS.
By default, [PostCSS] and [Autoprefixer] are installed with the boilerplate.
@@ -298,6 +301,9 @@ Example:
See [`styles.js`](../build/tasks/styles.js) for details.
The task also supports [PurgeCSS] to remove unused CSS.
See the [documentation on our Grid System](grid.md#build-tasks) for details.
### `svgs`
A wrapper around [SVG Mixer] for transforming and minifying SVG files
@@ -328,6 +334,80 @@ Example:
See [`svgs.js`](../build/tasks/svgs.js) for details.
### `versions`
A task to create and update values for use in versioning assets.
Can generate a hexadecimal value (using random bytes) or
use the current timestamp.
Example:
```json
{
"versions": [
{
"format": "timestamp",
"key": "now",
"outfile": "./assets.json"
},
{
"format": "hex:8",
"key": "hex",
"outfile": "./assets.json"
}
]
}
```
```json
{
"now": 1665071717350,
"hex": "6ef54181c4ba"
}
```
The task supports replacing the value of a data key in a JSON file or replacing
a string in a file using a [regular expression](RegExp).
* Explicit JSON field name:
```json
{
"key": "json:version"
}
```
* Implicit JSON field name:
```json
{
"key": "version"
}
```
The regular expression can be a `RegExp` object or a pattern prefixed with `regexp:`.
* ```json
{
"key": "regexp:(?<=^const ASSETS_VERSION = ')(?<build>\\d+)(?=';$)"
}
```
* ```js
{
key: new RegExp('(?<=^const ASSETS_VERSION = ')(?<version>\\d+)(?=';$)')
}
```
* ```js
{
key: /^ \* Version: +(?:.+?)\+(.+?)$/
}
```
The regular expression pattern will match the first occurrence and replace
the first match in the following order: `build` (named capture), `version`
(named capture), `1` (first capture), or `0` (whole match).
See [`versions.js`](../build/tasks/versions.js) for details.
[Autoprefixer]: https://npmjs.com/package/autoprefixer
[BrowserSync]: https://npmjs.com/package/browser-sync
[concat]: https://npmjs.com/package/concat
@@ -340,5 +420,7 @@ See [`svgs.js`](../build/tasks/svgs.js) for details.
[NPM]: https://npmjs.com/
[NVM]: https://github.com/nvm-sh/nvm
[PostCSS]: https://npmjs.com/package/postcss
[PurgeCSS]: https://purgecss.com/
[RegExp]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp
[SVG Mixer]: https://npmjs.com/package/svg-mixer
[tiny-glob]: https://npmjs.com/package/tiny-glob

2872
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@
"type": "module",
"engines": {
"node": ">=14.17",
"npm": ">=6.0"
"npm": ">=8.0"
},
"scripts": {
"start": "node --experimental-json-modules --no-warnings build/watch.js",
@@ -21,16 +21,21 @@
"svg4everybody": "^2.1.9"
},
"devDependencies": {
"autoprefixer": "^10.4.12",
"browser-sync": "^2.27.10",
"autoprefixer": "^10.4.13",
"browser-sync": "^2.27.11",
"concat": "^1.0.3",
"esbuild": "^0.14.54",
"esbuild": "^0.16.17",
"kleur": "^4.1.5",
"node-notifier": "^10.0.1",
"node-sass": "^7.0.1",
"postcss": "^8.4.17",
"node-sass": "^8.0.0",
"postcss": "^8.4.21",
"purgecss": "^5.0.0",
"svg-mixer": "^2.3.14",
"svg-mixer": "~2.3.14",
"tiny-glob": "^0.2.9"
},
"overrides": {
"svg-mixer": {
"postcss": "^8.4.20"
}
}
}

View File

@@ -539,7 +539,7 @@ button:focus, button:hover,
@font-face {
font-display: swap;
font-family: Source Sans;
font-family: "Source Sans";
src: url("../fonts/SourceSans3-Bold.woff2") format("woff2"), url("../fonts/SourceSans3-Bold.woff") format("woff");
font-weight: 700;
font-style: normal;
@@ -547,7 +547,7 @@ button:focus, button:hover,
@font-face {
font-display: swap;
font-family: Source Sans;
font-family: "Source Sans";
src: url("../fonts/SourceSans3-BoldIt.woff2") format("woff2"), url("../fonts/SourceSans3-BoldIt.woff") format("woff");
font-weight: 700;
font-style: italic;
@@ -555,7 +555,7 @@ button:focus, button:hover,
@font-face {
font-display: swap;
font-family: Source Sans;
font-family: "Source Sans";
src: url("../fonts/SourceSans3-Regular.woff2") format("woff2"), url("../fonts/SourceSans3-Regular.woff") format("woff");
font-weight: 400;
font-style: normal;
@@ -563,7 +563,7 @@ button:focus, button:hover,
@font-face {
font-display: swap;
font-family: Source Sans;
font-family: "Source Sans";
src: url("../fonts/SourceSans3-RegularIt.woff2") format("woff2"), url("../fonts/SourceSans3-RegularIt.woff") format("woff");
font-weight: 400;
font-style: italic;
@@ -572,9 +572,8 @@ button:focus, button:hover,
html {
min-height: 100%;
line-height: 1.5;
font-family: Source, Sans, -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif;
font-family: "Source Sans", -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif;
color: #000000;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

File diff suppressed because one or more lines are too long