@thegetty/quire-cli 1.0.0-rc.9 → 1.0.1-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +174 -7
  2. package/README.md +15 -0
  3. package/bin/cli.js +13 -7
  4. package/package.json +19 -14
  5. package/patches/README.md +19 -0
  6. package/patches/install-npm-version+1.0.9.patch +12119 -0
  7. package/src/Command.js +14 -0
  8. package/src/commands/conf.js +43 -0
  9. package/src/commands/create.js +13 -9
  10. package/src/commands/epub.js +1 -2
  11. package/src/commands/info.js +15 -10
  12. package/src/commands/pdf.js +60 -10
  13. package/src/commands/validate.js +64 -0
  14. package/src/errors/validation/validation-error.js +13 -0
  15. package/src/errors/validation/yaml-duplicate-error.js +11 -0
  16. package/src/errors/validation/yaml-parse-error.js +11 -0
  17. package/src/errors/validation/yaml-validation-error.js +11 -0
  18. package/src/helpers/clean.js +5 -0
  19. package/src/helpers/is-empty.js +4 -0
  20. package/src/helpers/is-quire.js +4 -0
  21. package/src/helpers/os-utils.js +4 -0
  22. package/src/helpers/test-cwd.js +4 -0
  23. package/src/helpers/which.js +4 -0
  24. package/src/lib/11ty/api.js +10 -28
  25. package/src/lib/11ty/cli.js +30 -8
  26. package/src/lib/conf/README.md +104 -0
  27. package/src/lib/conf/config.js +35 -0
  28. package/src/lib/conf/defaults.js +37 -0
  29. package/src/lib/conf/migrations.js +11 -0
  30. package/src/lib/conf/schema.js +30 -0
  31. package/src/lib/pdf/README.md +11 -4
  32. package/src/lib/pdf/index.js +4 -4
  33. package/src/lib/pdf/paged.js +88 -9
  34. package/src/lib/pdf/pagedPlugin.js +49 -0
  35. package/src/lib/pdf/prince.js +79 -4
  36. package/src/lib/pdf/princePlugin.js +35 -0
  37. package/src/lib/pdf/split.js +61 -0
  38. package/src/lib/quire/index.js +67 -144
  39. package/src/main.js +21 -6
  40. package/src/packageConfig.js +15 -0
  41. package/src/validators/utils.js +98 -0
  42. package/src/validators/validate-yaml.js +38 -0
  43. package/src/lib/config/README.md +0 -3
  44. package/src/lib/config/index.js +0 -1
package/src/Command.js CHANGED
@@ -1,3 +1,5 @@
1
+ import config from '#src/lib/conf/config.js'
2
+
1
3
  /**
2
4
  * Command
3
5
  * @abstract
@@ -12,6 +14,7 @@ export default class Command {
12
14
  /**
13
15
  * @typedef CommandDefinition
14
16
  * @property {String} name
17
+ * @property {String} alias
15
18
  * @property {Array<String>} aliases
16
19
  * @property {String} descriptions
17
20
  * @property {Array<CommandArgument>} args
@@ -24,6 +27,8 @@ export default class Command {
24
27
  /**
25
28
  * Constructs a new instance
26
29
  *
30
+ * Nota bene: Only the first command alias is displayed in the help.
31
+ *
27
32
  * @param {CommandDefinition} definition The definition
28
33
  */
29
34
  constructor(definition) {
@@ -31,6 +36,15 @@ export default class Command {
31
36
  throw new Error('Command is an *abstract* class')
32
37
  }
33
38
 
39
+ this.config = config // quire-cli configuration
40
+
41
+ /**
42
+ * Merge and deduplicate command definition alias and aliases
43
+ * Nota bene: Only the first command alias is displayed in the help.
44
+ */
45
+ // let aliases = Array.isArray(definition.aliases) ? definition.aliases || []
46
+ // aliases = new Set([ definition.alias, ...aliases ])
47
+
34
48
  this.name = definition.name
35
49
  this.aliases = definition.aliases
36
50
  this.description = definition.description
@@ -0,0 +1,43 @@
1
+ import Command from '#src/Command.js'
2
+
3
+ /**
4
+ * Quire CLI `conf` Command
5
+ *
6
+ * @class ConfCommand
7
+ * @extends {Command}
8
+ */
9
+ export default class ConfCommand extends Command {
10
+ static definition = {
11
+ name: 'conf',
12
+ aliases: ['config', 'configure'],
13
+ description: 'Manage the Quire CLI configuration.',
14
+ summary: 'read/write quire-cli configuration options',
15
+ version: '1.0.0',
16
+ options: [
17
+ [ '--debug', 'run command in debug mode' ],
18
+ ],
19
+ }
20
+
21
+ constructor() {
22
+ super(ConfCommand.definition)
23
+ }
24
+
25
+ /**
26
+ * @param {Object} options
27
+ * @return {Promise}
28
+ */
29
+ async action(key, value, options = {}) {
30
+ if (options.debug) {
31
+ console.info('Command \'%s\' called with options %o', this.name(), options)
32
+ }
33
+
34
+ // this.outputHelp()
35
+
36
+ console.info('quire-cli configuration %s', this.config.path)
37
+
38
+ for (const [ key, value ] of Object.entries(this.config.store)) {
39
+ if (key.startsWith('__internal__') && !options.debug) continue
40
+ console.info('%s: %O', key, value)
41
+ }
42
+ }
43
+ }
@@ -1,4 +1,5 @@
1
1
  import Command from '#src/Command.js'
2
+ import fs from 'fs-extra'
2
3
  import { quire } from '#src/lib/quire/index.js'
3
4
 
4
5
  /**
@@ -23,7 +24,7 @@ export default class CreateCommand extends Command {
23
24
  ],
24
25
  options: [
25
26
  [ '--quire-path <path>', 'local path to quire-11ty package' ],
26
- [ '--quire-version <version>', 'quire-11ty version to install', 'latest' ],
27
+ [ '--quire-version <version>', 'quire-11ty version to install' ],
27
28
  // [ '--eject', 'install quire-11ty into the project directory', true ],
28
29
  [ '--debug', 'debug the `quire new` command', false ],
29
30
  ],
@@ -44,6 +45,8 @@ export default class CreateCommand extends Command {
44
45
  console.info('Command \'%s\' called with options %o', CreateCommand.name, options)
45
46
  }
46
47
 
48
+ starter = starter || this.config.get('projectTemplate')
49
+
47
50
  if (!projectPath && !starter) {
48
51
  // @TODO implement this case of interactively selecting starter templates
49
52
  // from available subtrees in `lib/quire` module
@@ -60,15 +63,16 @@ export default class CreateCommand extends Command {
60
63
  * - interactive mode prompt to continue
61
64
  * - non-interactive mode throw an error and exit the process
62
65
  */
63
- await quire.initStarter(starter, projectPath, options)
64
-
65
- options.eject = true
66
-
67
- if (options.eject) {
68
- await quire.installInProject(projectPath, options)
69
- } else {
70
- await quire.install(options)
66
+ let quireVersion
67
+ try {
68
+ quireVersion = await quire.initStarter(starter, projectPath, options)
69
+ } catch (error) {
70
+ console.error(error.message)
71
+ fs.removeSync(projectPath)
72
+ return
71
73
  }
74
+
75
+ await quire.installInProject(projectPath, quireVersion, options)
72
76
  }
73
77
  }
74
78
  }
@@ -55,8 +55,7 @@ export default class EpubCommand extends Command {
55
55
  }
56
56
 
57
57
  /**
58
- * test if build site has already be run and output can be reused
59
- * @todo
58
+ * @todo test if build site has already be run and output can be reused
60
59
  */
61
60
  preAction(command) {
62
61
  const options = command.opts()
@@ -2,11 +2,9 @@ import Command from '#src/Command.js'
2
2
  import { execaCommand } from 'execa'
3
3
  import fs from 'node:fs'
4
4
  import os from 'node:os'
5
- import path from 'path'
5
+ import path from 'node:path'
6
6
  import testcwd from '#helpers/test-cwd.js'
7
7
 
8
- const VERSION_FILE = '.quire'
9
-
10
8
  /**
11
9
  * Quire CLI `info` Command
12
10
  *
@@ -22,7 +20,9 @@ export default class InfoCommand extends Command {
22
20
  summary: 'list info',
23
21
  version: '1.0.0',
24
22
  args: [],
25
- options: [['--debug', 'include os versions in output']],
23
+ options: [
24
+ ['--debug', 'include os versions in output']
25
+ ],
26
26
  }
27
27
 
28
28
  constructor() {
@@ -40,15 +40,20 @@ export default class InfoCommand extends Command {
40
40
  console.debug('[CLI] Command \'%s\' called', this.name())
41
41
  }
42
42
 
43
- let versionFile = fs.readFileSync(VERSION_FILE, { encoding: 'utf8' })
43
+ // Load filename from config with a default constraint if it doesn't exist
44
+ const versionFileName = this.config.get('versionFile')
45
+ let versionInfo = { cli: '<=1.0.0.rc-7' }
46
+
44
47
  try {
45
- versionFile = JSON.parse(versionFile)
48
+ const versionFileData = fs.readFileSync(versionFileName, { encoding: 'utf8' })
49
+
50
+ versionInfo = JSON.parse(versionFileData)
46
51
  } catch (error) {
47
52
  console.warn(
48
53
  `This project was generated with the quire-cli prior to version 1.0.0.rc-8. Updating the version file to the new format, though this project's version file will not contain specific starter version information.`
49
54
  )
50
- versionFile = { cli: '<=1.0.0.rc-7' }
51
- fs.writeFileSync(VERSION_FILE, JSON.stringify(versionFile))
55
+
56
+ fs.writeFileSync(versionFileName, JSON.stringify(versionInfo))
52
57
  }
53
58
 
54
59
  const { name: projectDirectory } = path.parse(process.cwd())
@@ -59,7 +64,7 @@ export default class InfoCommand extends Command {
59
64
  items: [
60
65
  {
61
66
  name: 'quire-cli',
62
- get: () => versionFile.cli,
67
+ get: () => versionInfo.cli,
63
68
  },
64
69
  {
65
70
  name: 'quire-11ty',
@@ -70,7 +75,7 @@ export default class InfoCommand extends Command {
70
75
  },
71
76
  {
72
77
  name: 'starter',
73
- get: () => versionFile.starter,
78
+ get: () => versionInfo.starter,
74
79
  },
75
80
  ],
76
81
  },
@@ -1,10 +1,50 @@
1
- import Command from '#src/Command.js'
2
1
  import { paths, projectRoot } from '#lib/11ty/index.js'
2
+ import Command from '#src/Command.js'
3
3
  import fs from 'fs-extra'
4
4
  import libPdf from '#lib/pdf/index.js'
5
5
  import open from 'open'
6
6
  import path from 'node:path'
7
- // import testcwd from '#helpers/test-cwd.js'
7
+ import { pathToFileURL } from 'node:url'
8
+ import yaml from 'js-yaml'
9
+
10
+ /**
11
+ * @function loadConfig(path) - loads and validates quire config, returns an empty object if not found
12
+ *
13
+ * @param {path} string - file path to config file
14
+ *
15
+ * @return {Object|undefined} User configuration object or undefined
16
+ *
17
+ * @todo consider hardcoding a version check against .quire / project's package.json ver
18
+ */
19
+ async function loadConfig(configPath) {
20
+ if (!fs.existsSync(configPath)) {
21
+ return undefined
22
+ }
23
+
24
+ const data = fs.readFileSync(configPath)
25
+ let config = yaml.load(data)
26
+
27
+ // NB: Schemas and validators are specific to the 11ty version of the project being built
28
+ const schemaPath = path.join(projectRoot,'_plugins','schemas','config.json')
29
+ const validatorPath = path.join(projectRoot, '_plugins', 'globalData', 'validator.js')
30
+
31
+ if (fs.existsSync(schemaPath) && fs.existsSync(validatorPath)) {
32
+
33
+ const { validateUserConfig } = await import(pathToFileURL(validatorPath))
34
+
35
+ const schemaJSON = fs.readFileSync(schemaPath)
36
+ const schema = JSON.parse(schemaJSON)
37
+
38
+ try {
39
+ config = validateUserConfig('config', config, { config: schema })
40
+ } catch (error) {
41
+ console.error(error)
42
+ process.exit(1)
43
+ }
44
+ }
45
+
46
+ return config
47
+ }
8
48
 
9
49
  /**
10
50
  * Quire CLI `pdf` Command
@@ -41,22 +81,32 @@ export default class PDFCommand extends Command {
41
81
  console.debug('[CLI] Command \'%s\' called with options %o', this.name(), options)
42
82
  }
43
83
 
44
- const input = path.join(projectRoot, paths.output, 'pdf.html')
84
+ const publicationInput = path.join(projectRoot, paths.output, 'pdf.html')
85
+ const coversInput = path.join(projectRoot, paths.output, 'pdf-covers.html')
45
86
 
46
- if (!fs.existsSync(input)) {
47
- console.error(`Unable to find PDF input at ${input}\nPlease first run the 'quire build' command.`)
48
- return
87
+ const quireConfig = await loadConfig(path.join(projectRoot,'content','_data','config.yaml'))
88
+
89
+ if (quireConfig === undefined) {
90
+ console.error(`[quire pdf]: ERROR Unable to find a configuration file at ${path.join(projectRoot,'content','_data','config.yaml')}\nIs the command being run in a quire project?`)
91
+ process.exit(1)
92
+ }
93
+
94
+ if (!fs.existsSync(publicationInput)) {
95
+ console.error(`[quire pdf]: ERROR Unable to find PDF input at ${publicationInput}\nPlease first run the 'quire build' command.`)
96
+ process.exit(1)
49
97
  }
50
98
 
51
- const output = path.join(projectRoot, `${options.lib}.pdf`)
99
+ const output = quireConfig.pdf !== undefined
100
+ ? path.join(paths.output, quireConfig.pdf.outputDir, `${quireConfig.pdf.filename}.pdf`)
101
+ : path.join(projectRoot, `${options.lib}.pdf`)
52
102
 
53
- const pdfLib = await libPdf(options.lib, { debug: options.debug })
54
- await pdfLib(input, output)
103
+ const pdfLib = await libPdf(options.lib, { ...options, pdfConfig: quireConfig.pdf })
104
+ await pdfLib(publicationInput, coversInput, output)
55
105
 
56
106
  try {
57
107
  if (fs.existsSync(output) && options.open) open(output)
58
108
  } catch (error) {
59
- console.error(error)
109
+ console.error(`[quire pdf]: ERROR`,error)
60
110
  process.exit(1)
61
111
  }
62
112
  }
@@ -0,0 +1,64 @@
1
+ import Command from '#src/Command.js'
2
+ import { YAMLException } from 'js-yaml'
3
+ import YamlValidationError from '../errors/validation/yaml-validation-error.js'
4
+ import fs from 'fs-extra'
5
+ import path from 'node:path'
6
+ import { projectRoot } from '#lib/11ty/index.js'
7
+ import testcwd from '../helpers/test-cwd.js'
8
+ import yamlValidation from '../validators/validate-yaml.js'
9
+
10
+
11
+ /**
12
+ * Quire CLI `validate` Command
13
+ *
14
+ * @class ValidateCommand
15
+ * @extends {Command}
16
+ */
17
+ export default class ValidateCommand extends Command {
18
+ static definition = {
19
+ name: 'validate',
20
+ description: 'Validate configuration files',
21
+ summary: 'run validation',
22
+ version: '1.0.0',
23
+ options: [
24
+ [ '--debug', 'run validate with debug output to console' ],
25
+ ],
26
+ }
27
+
28
+ constructor() {
29
+ super(ValidateCommand.definition)
30
+ }
31
+
32
+ action(options, command){
33
+ if(options.debug) {
34
+ console.debug('[CLI] Command \'%s\' called with options %o', this.name(), options)
35
+ }
36
+
37
+ const dataPath = path.join(projectRoot, 'content', '_data')
38
+ const files = fs.readdirSync(dataPath)
39
+ .filter(file => file.endsWith('.yaml') || file.endsWith('.yml'))
40
+ .map(file => path.join(dataPath, file)
41
+ )
42
+
43
+ let errorList = []
44
+ console.log('Validating YAML files..')
45
+
46
+ for (const file of files) {
47
+ try {
48
+ yamlValidation(file)
49
+ } catch (error){
50
+ errorList.push(error)
51
+ }
52
+ }
53
+
54
+ if(errorList.length > 0) {
55
+ errorList.forEach(err => { console.error(`${err.reason}`) })
56
+ } else {
57
+ console.log('Validation complete.')
58
+ }
59
+ }
60
+
61
+ preAction(options, command) {
62
+ testcwd(command)
63
+ }
64
+ }
@@ -0,0 +1,13 @@
1
+ export default class ValidationError extends Error {
2
+ constructor(message, {filePath, reason, code} = {}) {
3
+ super(message)
4
+ this.name = this.constructor.name
5
+ this.filePath = filePath
6
+ this.reason = reason
7
+ this.code = code
8
+
9
+ if ('captureStackTrace' in Error) {
10
+ Error.captureStackTrace(this, this.constructor)
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,11 @@
1
+ import ValidationError from './validation-error.js'
2
+
3
+ export default class YamlDuplicateIdError extends ValidationError {
4
+ constructor(filePath, reason) {
5
+ super('Duplicate ID found in YAML file', {
6
+ filePath,
7
+ reason: reason,
8
+ code: 'YAML_DUPLICATE_ID_ERROR',
9
+ })
10
+ }
11
+ }
@@ -0,0 +1,11 @@
1
+ import ValidationError from './validation-error.js'
2
+
3
+ export default class YamlParseError extends ValidationError {
4
+ constructor(filePath, reason) {
5
+ super('Error parsing YAML file', {
6
+ filePath,
7
+ reason: reason,
8
+ code: 'YAML_PARSE_ERROR',
9
+ })
10
+ }
11
+ }
@@ -0,0 +1,11 @@
1
+ import ValidationError from './validation-error.js'
2
+
3
+ export default class YamlValidationError extends ValidationError {
4
+ constructor(filePath, reason) {
5
+ super('Error validating YAML file', {
6
+ filePath,
7
+ reason: reason,
8
+ code: 'YAML_VALIDATION_ERROR',
9
+ })
10
+ }
11
+ }
@@ -1,3 +1,7 @@
1
+ /**
2
+ * A helper module for cleaning quire outputs
3
+ * @module clean
4
+ */
1
5
  import { deleteAsync } from 'del'
2
6
  import path from 'node:path'
3
7
 
@@ -9,6 +13,7 @@ import path from 'node:path'
9
13
  */
10
14
  export async function clean (projectRoot, paths, options = {}) {
11
15
  const pathsToClean = [
16
+ path.join(projectRoot, '.11ty-vite'),
12
17
  path.join(projectRoot, paths.epub),
13
18
  path.join(projectRoot, paths.output),
14
19
  path.join(projectRoot, '*.epub'),
@@ -1,3 +1,7 @@
1
+ /**
2
+ * A helper module to test if a path is an empty directory
3
+ * @module is-empty
4
+ */
1
5
  import fs from 'node:fs'
2
6
 
3
7
  /**
@@ -1,3 +1,7 @@
1
+ /**
2
+ * A helper module to test if a directory is a Quire project root
3
+ * @module is-quire
4
+ */
1
5
  import fs from 'node:fs'
2
6
 
3
7
  const QUIRE_DOT_FILES = Object.freeze([
@@ -1,3 +1,7 @@
1
+ /**
2
+ * A helper module for cross platform dynamic imports
3
+ * @module os-utils
4
+ */
1
5
  import { pathToFileURL } from 'node:url'
2
6
 
3
7
  /**
@@ -1,3 +1,7 @@
1
+ /**
2
+ * A helper module to test the current working directory
3
+ * @module test-csd
4
+ */
1
5
  import isQuire from '#helpers/is-quire.js'
2
6
 
3
7
  /**
@@ -1,3 +1,7 @@
1
+ /**
2
+ * A helper module to wrap the `which` utility
3
+ * @module which
4
+ */
1
5
  import which from 'which'
2
6
 
3
7
  /**
@@ -42,6 +42,7 @@ const factory = async (options = {}) => {
42
42
  process.env.ELEVENTY_DATA = paths.data
43
43
  process.env.ELEVENTY_INCLUDES = paths.includes
44
44
  process.env.ELEVENTY_LAYOUTS = paths.layouts
45
+ process.env.QUIRE_DEBUG_LOG = options.debug
45
46
 
46
47
  /**
47
48
  * Get an instance of the runtime of eleventy.
@@ -50,37 +51,12 @@ const factory = async (options = {}) => {
50
51
  * @param {String} input Path from which to read content templates
51
52
  * @param {String} output Path where rendered files will be written
52
53
  * @param {Object} options Options are merged with the Eleventy UserConfig
53
- * @param {Object} config An eleventy configurtion object
54
+ * @property {string} config Config callback run after initialization
54
55
  *
55
56
  * @returns {module:11ty/eleventy/Eleventy~Eleventy}
56
57
  */
57
58
  const eleventy = new Eleventy(input, output, {
58
59
  config: (eleventyConfig) => {
59
- /**
60
- * Override addPassthroughCopy to use _absolute_ system paths.
61
- * @see https://www.11ty.dev/docs/copy/#passthrough-file-copy
62
- * Nota bene: Eleventy addPassthroughCopy assumes paths are _relative_
63
- * to the `config` file however the quire-cli separates 11ty from the
64
- * project directory (`input`) and needs to use absolute system paths.
65
- */
66
- const addPassthroughCopy = eleventyConfig.addPassthroughCopy.bind(eleventyConfig)
67
- eleventyConfig.addPassthroughCopy = (entry) => {
68
- if (typeof entry === 'string') {
69
- const filePath = path.resolve(entry) //path.join(projectRoot, file)
70
- // console.debug('[11ty:API] passthrough copy %s', filePath)
71
- return addPassthroughCopy(filePath, copyOptions)
72
- } else {
73
- // console.debug('[11ty:API] passthrough copy %o', entry)
74
- entry = Object.fromEntries(
75
- Object.entries(entry).map(([ src, dest ]) => {
76
- return [ path.join(eleventyRoot, src), path.resolve(dest) ]
77
- })
78
- )
79
- // console.debug('[11ty:API] passthrough copy %o', entry)
80
- return addPassthroughCopy(entry, copyOptions)
81
- }
82
- }
83
-
84
60
  /**
85
61
  * Event callback when a build completes
86
62
  * @see https://www.11ty.dev/docs/events/#eleventy.after
@@ -88,11 +64,10 @@ const factory = async (options = {}) => {
88
64
  eleventyConfig.on('eleventy.after', async () => {
89
65
  console.debug('[11ty:API] build complete')
90
66
  })
91
-
92
- return eleventyConfig
93
67
  },
94
68
  configPath: options.config || config,
95
69
  quietMode: options.quiet || false,
70
+ runMode: process.env.ELEVENTY_ENV === 'production' ? 'build' : 'serve'
96
71
  })
97
72
 
98
73
  return eleventy
@@ -127,7 +102,14 @@ export default {
127
102
  if (options.debug) process.env.DEBUG = 'Eleventy*'
128
103
 
129
104
  const eleventy = await factory(options)
105
+ await eleventy.init()
106
+ await eleventy.watch()
130
107
 
131
108
  await eleventy.serve(options.port)
109
+
110
+ process.on("SIGINT", async () => {
111
+ await eleventy.stopWatch()
112
+ process.exit(0)
113
+ })
132
114
  }
133
115
  }
@@ -1,4 +1,5 @@
1
1
  import { execa } from 'execa'
2
+ import fs from 'node:fs'
2
3
  import path from 'node:path'
3
4
  import paths, { eleventyRoot, projectRoot } from './paths.js'
4
5
 
@@ -17,16 +18,30 @@ const factory = (options = {}) => {
17
18
 
18
19
  /**
19
20
  * Use the version of Eleventy installed to `lib/quire/versions`
21
+ *
22
+ * NB: in eleventy v3 the CLI extension (".cjs") is load-bearing but v2 is simply ".js"
23
+ *
20
24
  */
21
- const eleventy =
22
- path.join(eleventyRoot, 'node_modules', '@11ty', 'eleventy', 'cmd.js')
25
+ const eleventyModuleDir = path.join(eleventyRoot, 'node_modules', '@11ty', 'eleventy')
26
+ const packagePath = path.join(eleventyModuleDir,'package.json')
27
+
28
+ const pack = JSON.parse(fs.readFileSync(packagePath))
29
+
30
+ const { version } = pack
31
+
32
+ const eleventyMajorVer = version.split('.').at(0)
33
+
34
+ let eleventy = path.join(eleventyModuleDir,'cmd.cjs')
35
+
36
+ if ( Number(eleventyMajorVer) < 3 ) {
37
+ eleventy = path.join(eleventyModuleDir,'cmd.js')
38
+ }
23
39
 
24
40
  const command = [
25
41
  eleventy,
26
42
  `--config=${config}`,
27
43
  `--input=${input}`,
28
- `--output=${output}`,
29
- `--incremental`,
44
+ `--output=${output}`
30
45
  ]
31
46
 
32
47
  if (options.quiet) command.push('--quiet')
@@ -46,6 +61,7 @@ const factory = (options = {}) => {
46
61
  ELEVENTY_DATA: paths.data,
47
62
  ELEVENTY_INCLUDES: paths.includes,
48
63
  ELEVENTY_LAYOUTS: paths.layouts,
64
+ QUIRE_DEBUG_LOG: options.debug
49
65
  }
50
66
 
51
67
  if (options.debug) env.DEBUG = 'Eleventy*'
@@ -67,12 +83,18 @@ export default {
67
83
 
68
84
  env.ELEVENTY_ENV = 'production'
69
85
 
70
- await execa('node', command, {
86
+ const build = execa('node', command, {
71
87
  all: true,
72
88
  cwd: projectRoot,
73
89
  env,
74
- execPath: process.execPath
75
- }).all.pipe(process.stdout)
90
+ nodePath: process.execPath
91
+ })
92
+ build.all.pipe(process.stdout)
93
+ await build
94
+
95
+ if (build.exitCode !== 0) {
96
+ process.exit(build.exitCode)
97
+ }
76
98
  },
77
99
 
78
100
  serve: async (options = {}) => {
@@ -90,7 +112,7 @@ export default {
90
112
  all: true,
91
113
  cwd: projectRoot,
92
114
  env,
93
- execPath: process.execPath
115
+ nodePath: process.execPath
94
116
  }).all.pipe(process.stdout)
95
117
  }
96
118
  }