Skip to content

Commit 27903a8

Browse files
authored
RELEASE: v2.36.1
* Fixed an issue with the build system that was producing subtly broken builds.
2 parents 7d7c866 + a1251d8 commit 27903a8

19 files changed

+5513
-5791
lines changed

.browserslistrc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# WARNING: The `defaults` query must be explicitly spelled out or various
2+
# plugins—e.g., `@babel/preset-env`—will not properly process the aggregate
3+
# query.
4+
5+
> 1% or last 3 versions or last 10 Chrome versions or last 10 Firefox versions or IE >= 9 or Opera >= 12

.eslintrc.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"parserOptions" : {
3-
"ecmaVersion": 6
3+
"ecmaVersion": 2021
44
},
55
"env" : {
66
"browser" : true,
7-
"es6" : true,
7+
"es2021" : true,
88
"jquery" : true
99
},
1010
"globals": {

.stylelintignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# JavaScript
2+
**/*.js
3+
4+
# Vendored
5+
vendor/
6+
7+
# Development
8+
build/
9+
node_modules/

.stylelintrc.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"extends" : [
3+
"stylelint-config-standard"
4+
],
5+
"reportNeedlessDisables" : true,
6+
"rules" : {
7+
"at-rule-no-unknown" : [true, { "ignoreAtRules": ["define-mixin", "mixin"] }],
8+
"at-rule-empty-line-before" : null,
9+
"comment-empty-line-before" : null,
10+
"indentation" : "tab",
11+
"linebreaks" : "unix",
12+
"max-empty-lines" : 2,
13+
"no-descending-specificity" : null,
14+
"rule-empty-line-before" : null,
15+
"selector-class-pattern" : "^([a-z][a-z0-9]*)(-[a-z0-9]+)*$"
16+
}
17+
}

.vscode/settings.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"editor.insertSpaces": false,
3+
"css.validate": false
4+
}

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ You may either download one of the precompiled packages from [SugarCube's websit
1414

1515
If you want to build SugarCube from scratch, rather than grabbing one of the pre-built packages off of its website, then these instructions are for you.
1616

17-
SugarCube uses Node.js as the core of its build system, so you'll need to install it if you don't already have it. Additionally, to retrieve SugarCube's source code from this repository, you'll need to install Git.
17+
SugarCube uses Node.js (currently ≥v16) as the core of its build system, so you'll need to install it if you don't already have it. Additionally, to retrieve SugarCube's source code from this repository, you'll need to install Git.
1818

1919
1. [Download and install the Node.js JavaScript runtime (`https://nodejs.org/`)](https://nodejs.org/)
2020
2. [Download and install the Git source control management tool (`https://git-scm.com/`)](https://git-scm.com/)
@@ -52,7 +52,7 @@ node build.js
5252

5353
Assuming that completed with no errors, the story format, in Twine 1 and Twine 2 flavors, should be output to the `dist` directory. Congratulations!
5454

55-
**NOTE:** SugarCube's development dependencies are occasionally updated. If you receive errors when attempting to build, then you probably need to update your cached dependencies. You may do this via the `npm update` command or, in extreme cases, by deleting the local `node_modules` directory and rerunning `npm install`.
55+
**NOTE:** SugarCube's development dependencies are occasionally updated. If you receive errors when attempting to build, then you probably need to update your cached dependencies. You may do this via the `npm update` command or, in extreme cases, by running `npm uninstall` and `npm install` in order.
5656

5757
**TIP:** If you'd like additional options when building—e.g., debug builds, limiting the build to a particular version of Twine, etc.—then you may request help from `build.js` by specifying the help (`-h`, `--help`) option. For example:
5858

browserslist

Lines changed: 0 additions & 8 deletions
This file was deleted.

build.js

Lines changed: 102 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
#!/usr/bin/env node
22
/***********************************************************************************************************************
33
4-
build.js (v1.6.0, 2021-12-19)
4+
build.js (v1.7.1, 2021-12-21)
55
A Node.js-hosted build script for SugarCube.
66
77
Copyright © 2013–2021 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.
88
Use of this source code is governed by a BSD 2-clause "Simplified" License, which may be found in the LICENSE file.
99
1010
***********************************************************************************************************************/
11-
/* eslint-env node, es6 */
11+
/* eslint-env node, es2021 */
1212
'use strict';
1313

14+
1415
/*******************************************************************************
1516
Configuration
1617
*******************************************************************************/
18+
1719
const CONFIG = {
1820
js : {
19-
main : [
21+
files : [
2022
// The ordering herein is significant.
2123
'src/lib/alert.js',
2224
'src/lib/patterns.js',
@@ -67,20 +69,23 @@ const CONFIG = {
6769
outro : 'src/templates/outro.js'
6870
}
6971
},
70-
css : [
71-
// The ordering herein is significant.
72-
'src/vendor/normalize.css',
73-
'src/css/init-screen.css',
74-
'src/css/font.css',
75-
'src/css/core.css',
76-
'src/css/core-display.css',
77-
'src/css/core-passage.css',
78-
'src/css/core-macro.css',
79-
'src/css/ui-dialog.css',
80-
'src/css/ui.css',
81-
'src/css/ui-bar.css',
82-
'src/css/ui-debug.css'
83-
],
72+
css : {
73+
mixins : 'src/css/_mixins.css',
74+
files : [
75+
// The ordering herein is significant.
76+
'src/vendor/normalize.css',
77+
'src/css/init-screen.css',
78+
'src/css/font.css',
79+
'src/css/core.css',
80+
'src/css/core-display.css',
81+
'src/css/core-passage.css',
82+
'src/css/core-macro.css',
83+
'src/css/ui-dialog.css',
84+
'src/css/ui.css',
85+
'src/css/ui-bar.css',
86+
'src/css/ui-debug.css'
87+
]
88+
},
8489
libs : [
8590
// The ordering herein is significant.
8691
'src/vendor/classList.min.js',
@@ -133,13 +138,12 @@ const CONFIG = {
133138
/*******************************************************************************
134139
Main Script
135140
*******************************************************************************/
136-
/*
137-
NOTICE!
138141

139-
Where string replacements are done, we use the replacement function style here to
140-
disable all special replacement patterns, since some of them likely exist within
141-
the replacement strings (e.g. '$&' within the application source).
142-
*/
142+
// NOTICE!
143+
//
144+
// Where string replacements are done, we use the replacement function style to
145+
// disable all special replacement patterns, since some of them may exist within
146+
// the replacement strings—e.g., `$&` within the HTML or JavaScript sources.
143147

144148
const {
145149
log,
@@ -156,21 +160,15 @@ const _opt = require('node-getopt').create([
156160
['b', 'build=VERSION', 'Build only for Twine major version: 1 or 2; default: build for all.'],
157161
['d', 'debug', 'Keep debugging code; gated by DEBUG symbol.'],
158162
['u', 'unminified', 'Suppress minification stages.'],
159-
['6', 'es6', 'Suppress JavaScript transpilation stages.'],
163+
['n', 'no-transpile', 'Suppress JavaScript transpilation stages.'],
160164
['h', 'help', 'Print this help, then exit.']
161165
])
162-
.bindHelp() // bind option 'help' to default action
163-
.parseSystem(); // parse command line
164-
165-
// uglify-js (v2) does not currently support ES6, so force `unminified` when `es6` is enabled.
166-
if (_opt.options.es6 && !_opt.options.unminified) {
167-
_opt.options.unminified = true;
168-
}
166+
.bindHelp()
167+
.parseSystem();
169168

170169
let _buildForTwine1 = true;
171170
let _buildForTwine2 = true;
172171

173-
// build selection
174172
if (_opt.options.build) {
175173
switch (_opt.options.build) {
176174
case '1':
@@ -187,8 +185,8 @@ if (_opt.options.build) {
187185
}
188186
}
189187

190-
// build the project
191-
(() => {
188+
// Build the project.
189+
(async () => {
192190
console.log('Starting builds...');
193191

194192
// Create the build ID file, if nonexistent.
@@ -226,9 +224,9 @@ if (_opt.options.build) {
226224
projectBuild({
227225
build : CONFIG.twine1.build,
228226
version : version, // eslint-disable-line object-shorthand
229-
libSource : assembleLibraries(CONFIG.libs), // combine the libraries
230-
appSource : compileJavaScript(CONFIG.js, { twine1 : true }), // combine and minify the app JS
231-
cssSource : compileStyles(CONFIG.css) // combine and minify the app CSS
227+
libSource : assembleLibraries(CONFIG.libs), // combine the libraries
228+
appSource : await compileJavaScript(CONFIG.js, { twine1 : true }), // combine and minify the app JS
229+
cssSource : compileStyles(CONFIG.css) // combine and minify the app CSS
232230
});
233231

234232
// Process the files that simply need copied into the build.
@@ -243,9 +241,9 @@ if (_opt.options.build) {
243241
projectBuild({
244242
build : CONFIG.twine2.build,
245243
version : version, // eslint-disable-line object-shorthand
246-
libSource : assembleLibraries(CONFIG.libs), // combine the libraries
247-
appSource : compileJavaScript(CONFIG.js, { twine1 : false }), // combine and minify the app JS
248-
cssSource : compileStyles(CONFIG.css), // combine and minify the app CSS
244+
libSource : assembleLibraries(CONFIG.libs), // combine the libraries
245+
appSource : await compileJavaScript(CONFIG.js, { twine1 : false }), // combine and minify the app JS
246+
cssSource : compileStyles(CONFIG.css), // combine and minify the app CSS
249247

250248
postProcess(sourceString) {
251249
// Load the output format.
@@ -274,10 +272,9 @@ if (_opt.options.build) {
274272

275273
// Update the build ID.
276274
writeFileContents('.build', String(version.build));
277-
})();
278-
279-
// That's all folks!
280-
console.log('\nBuilds complete! (check the "build" directory)');
275+
})()
276+
.then(() => console.log('\nBuilds complete! (check the "build" directory)'))
277+
.catch(reason => console.log('\nERROR:', reason));
281278

282279

283280
/*******************************************************************************
@@ -290,86 +287,92 @@ function assembleLibraries(filenames) {
290287
}
291288

292289
function compileJavaScript(filenameObj, options) {
293-
/* eslint-disable camelcase, prefer-template */
294290
log('compiling JavaScript...');
295291

296-
const babelCore = require('babel-core');
297-
const babelOpts = {
298-
code : true,
299-
compact : false,
300-
presets : ['env'],
301-
filename : 'sugarcube.js'
302-
};
303-
304-
// Join the files and transpile (ES6 → ES5) with Babel.
305-
let jsSource = concatFiles(filenameObj.main);
306-
jsSource = readFileContents(filenameObj.wrap.intro)
307-
+ '\n'
308-
+ (_opt.options.es6 ? jsSource : babelCore.transform(jsSource, babelOpts).code)
309-
+ '\n'
310-
+ readFileContents(filenameObj.wrap.outro);
311-
312-
if (_opt.options.unminified) {
313-
return [
314-
'window.TWINE1=' + String(!!options.twine1),
315-
'window.DEBUG=' + String(_opt.options.debug || false)
316-
].join(';\n') + ';\n' + jsSource;
292+
// Join the files.
293+
let bundle = concatFiles(filenameObj.files);
294+
295+
// Transpile to ES5 with Babel.
296+
if (!_opt.options.noTranspile) {
297+
const { transform } = require('@babel/core');
298+
bundle = transform(bundle, {
299+
// babelHelpers : 'bundled',
300+
code : true,
301+
compact : false,
302+
presets : [['@babel/preset-env']],
303+
filename : 'sugarcube.bundle.js'
304+
}).code;
317305
}
318306

319-
const uglifyjs = require('uglify-js');
320-
const minified = uglifyjs.minify(jsSource, {
321-
compress : {
322-
global_defs : {
323-
TWINE1 : !!options.twine1,
324-
DEBUG : _opt.options.debug || false
307+
bundle = `${readFileContents(filenameObj.wrap.intro)}\n${bundle}\n${readFileContents(filenameObj.wrap.outro)}`;
308+
309+
return (async source => {
310+
if (_opt.options.unminified) {
311+
return [
312+
`window.TWINE1=${Boolean(options.twine1)}`,
313+
`window.DEBUG=${_opt.options.debug || false}`,
314+
source
315+
].join(';\n');
316+
}
317+
318+
// Minify the code with Terser.
319+
const { minify } = require('terser');
320+
const minified = await minify(source, {
321+
compress : {
322+
global_defs : { // eslint-disable-line camelcase
323+
TWINE1 : !!options.twine1,
324+
DEBUG : _opt.options.debug || false
325+
}
325326
},
326-
keep_infinity : true
327-
},
328-
mangle : false
329-
});
327+
mangle : false
328+
});
330329

331-
if (minified.error) {
332-
const { message, line, col, pos } = minified.error;
333-
die(`JavaScript minification error: ${message}\n[@: ${line}/${col}/${pos}]`);
334-
}
330+
if (minified.error) {
331+
const { message, line, col, pos } = minified.error;
332+
die(`JavaScript minification error: ${message}\n[@: ${line}/${col}/${pos}]`);
333+
}
335334

336-
return minified.code;
337-
/* eslint-enable camelcase, prefer-template */
335+
return minified.code;
336+
})(bundle);
338337
}
339338

340-
function compileStyles(filenames) {
341-
/* eslint-disable prefer-template */
339+
function compileStyles(config) {
342340
log('compiling CSS...');
343341

344-
const postcss = require('postcss');
345-
const CleanCss = require('clean-css');
346-
const normalizeRegExp = /normalize\.css$/;
342+
const autoprefixer = require('autoprefixer');
343+
const mixins = require('postcss-mixins');
344+
const postcss = require('postcss');
345+
const CleanCSS = require('clean-css');
346+
const excludeRE = /(?:normalize)\.css$/;
347+
const mixinContent = readFileContents(config.mixins);
347348

348-
return concatFiles(filenames, (contents, filename) => {
349+
return concatFiles(config.files, (contents, filename) => {
349350
let css = contents;
350351

351-
// Don't run autoprefixer on 'normalize.css'.
352-
if (!normalizeRegExp.test(filename)) {
353-
const processed = postcss([require('autoprefixer')]).process(css, { from : filename });
352+
// Do not run the postcss plugins on files that match the exclusion regexp.
353+
if (!excludeRE.test(filename)) {
354+
css = `${mixinContent}\n${css}`;
355+
356+
const processed = postcss([mixins, autoprefixer]).process(css, { from : filename });
354357

355358
css = processed.css;
356359

357360
processed.warnings().forEach(mesg => console.warn(mesg.text));
358361
}
359362

360363
if (!_opt.options.unminified) {
361-
css = new CleanCss({
362-
level : 1, // [clean-css v4] `1` is the default, but let's be specific
363-
compatibility : 'ie9' // [clean-css v4] 'ie10' is the default, so restore IE9 support
364+
css = new CleanCSS({
365+
level : 1,
366+
compatibility : 'ie9'
364367
})
365368
.minify(css)
366369
.styles;
367370
}
368371

369-
return '<style id="style-' + _path.basename(filename, '.css').toLowerCase().replace(/[^0-9a-z]+/g, '-')
370-
+ '" type="text/css">' + css + '</style>';
372+
const fileSlug = _path.basename(filename, '.css').toLowerCase().replace(/[^0-9a-z]+/g, '-');
373+
374+
return `<style id="style-${fileSlug}" type="text/css">${css}</style>`;
371375
});
372-
/* eslint-enable prefer-template */
373376
}
374377

375378
function projectBuild(project) {
@@ -378,7 +381,8 @@ function projectBuild(project) {
378381

379382
log(`building: "${outfile}"`);
380383

381-
let output = readFileContents(infile); // load the story format template
384+
// Load the story format template.
385+
let output = readFileContents(infile);
382386

383387
// Process the source replacement tokens. (First!)
384388
output = output.replace(/(['"`])\{\{BUILD_LIB_SOURCE\}\}\1/, () => project.libSource);

dist/format.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)