Skip to content
This repository has been archived by the owner on Mar 14, 2024. It is now read-only.

Add isolate feature #3920

Merged
merged 12 commits into from
Sep 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .huskyrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"//1": "Use git commit --no-verify to bypass the pre-commit hook",
"//2": "Use git push --no-verify to bypass the pre-push hook",
"hooks": {
"pre-push": "npm run lint"
"pre-push": "npm run lint",
"pre-commit": "node ./tools/isolate restored"
}
}
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,43 @@ npm run dev
Open `http://localhost:8080/` to see the site locally. Changes to assets will
rebuild the site. Refresh to see your changes.

### Speeding up builds

⚠️ This is an experimental feature 🧪🔬

Any change to the site will cause Eleventy to rebuild. This can take 10-20s. If
you want to speed things up you can isolate your directory using the `isolate`
command.

```bash
npm run isolate
```

This will move all of the markdown files for the site into the `_exile`
directory and it will ignore them for builds.

You may pass an optional glob (or space separated list of globs) to the
`isolate` command to tell it to preserve a directory.

```bash
# Example 1: Preserve the style-focus directory
# note the -- which is needed to pass options to npm scripts
npm run isolate -- src/site/content/en/accessible/style-focus/**

# Example 2: Preserve everything in the accessible directory
npm run isolate -- src/site/content/en/accessible/**/*
```

When you're finished making your edits, run the `integrate` command to restore
all of the project files.

```bash
npm run integrate
```

☝️ A git commit hook will prevent you from being able to run `git commit` until
you have run the `integrate` command.

## Environments 🌳

Set `ELEVENTY_ENV=prod` to force production builds. This is the default when
Expand Down
37 changes: 34 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
"eleventy": "eleventy --quiet",
"gulp": "npx gulp build",
"karma": "karma start",
"isolate": "node ./tools/isolate isolate",
"integrate": "node ./tools/isolate integrate",
"lint:js": "gts check",
"lint:md": "remark -q -f .",
"lint:scss": "sass-lint -v -q",
Expand Down Expand Up @@ -89,6 +91,7 @@
"eleventy-plugin-toc": "^1.1.0",
"fancy-log": "^1.3.3",
"firebase": "^7.14.6",
"glob": "^7.1.6",
"gts": "^2.0.2",
"gulp": "^4.0.0",
"gulp-imagemin": "^7.1.0",
Expand All @@ -109,6 +112,7 @@
"markdown-it-attrs": "^3.0.0",
"mocha": "^6.2.0",
"moment": "^2.24.0",
"move-file": "^2.0.0",
"node-fetch": "^2.3.0",
"npm-run-all": "^4.1.5",
"postcss": "^7.0.27",
Expand Down
8 changes: 0 additions & 8 deletions src/site/_collections/authors.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,6 @@ module.exports = (collections) => {
authors[key] = author;
});

// Only complain that authors are invalid if we've got any posts *at all*
robdodson marked this conversation as resolved.
Show resolved Hide resolved
// (we can do weird Eleventy builds with no posts, don't complain here).
const isRegularBuild = Boolean(allPosts.length);
if (isRegularBuild && invalidAuthors.length) {
const s = invalidAuthors.join(',');
throw new Error(`authors [${s}] have no posts and/or Twitter information`);
}

if (collections) {
processedCollection = authors;
}
Expand Down
82 changes: 82 additions & 0 deletions tools/isolate/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/* eslint-disable no-process-exit */

const util = require('util');
const path = require('path');
const glob = util.promisify(require('glob'));
const mv = require('move-file');
const fs = require('fs').promises;
const {existsSync} = require('fs');

const exileDir = '_exile';
const exilePath = `src/site/${exileDir}`;
const contentDir = 'content';
const contentPath = `src/site/${contentDir}`;
const globPattern = '**/{feed.njk,*.md}';

/**
* Move all markdown files and RSS feeds in src/site/content to the _exile
* directory.
* Optionally pass in an array of globs to be ignored.
* Items matching these globs will not be moved to _exile.
* @param {Array<string>} ignore An array of glob patterns to be ignored.
*/
async function isolate(ignore = []) {
robdodson marked this conversation as resolved.
Show resolved Hide resolved
// Check if the _exile directory already exists to avoid the user
// accidentally running isolate twice.
restored();
// Eleventy's rssLastUpdatedDate filter will blow up if we pass it an empty
// collection. To avoid this we also move all RSS feeds into exile.
const matches = await glob(path.join(contentPath, globPattern), {ignore});
for (const oldPath of matches) {
let newPath = oldPath.split(path.sep);
newPath.splice(2, 1, exileDir);
newPath = newPath.join(path.sep);
await mv(oldPath, newPath);
}
}

/**
* Restore files in _exile to their original location in src/site/content.
* Removes the _exile dir when it is finished.
*/
async function integrate() {
const matches = await glob(path.join(exilePath, globPattern));
for (const oldPath of matches) {
let newPath = oldPath.split(path.sep);
newPath.splice(2, 1, contentDir);
newPath = newPath.join(path.sep);
await mv(oldPath, newPath);
}
await fs.rmdir(exilePath, {recursive: true});
}

/**
* Verify that the _exile directory does not exist.
* This can be used by git commit hooks to prevent folks from committing while
* in an isolated state.
*/
function restored() {
if (existsSync(exilePath)) {
throw new Error(
'Found _exile directory. You need to run: npm run integrate.',
);
}
}

const allowedCommands = ['isolate', 'integrate', 'restored'];
const command = process.argv[2];
if (allowedCommands.indexOf(command) === -1) {
throw new Error(
// prettier-ignore
`Invalid command: ${command}. Command must be one of the following: ${allowedCommands.join(', ')}.`,
);
}
const ignore = process.argv.slice(3);
switch (command) {
case 'isolate':
return isolate(ignore);
case 'integrate':
return integrate();
case 'restored':
return restored();
}