src/raw -> static, verbatim and without an extension whitelist. the tree for files that are served rather than generated:favicon.ico,robots.txt, images, fonts. it is the piece that lets a project saystatic/is entirely derived - and once that is true,rm -rf staticis safe and the directory does not belong in version control. a whitelist there could only mean silently failing to ship a file someone added, so there is none; see theignorednote below for what stops a.DS_Storeinstead.raw: falseturns it off. it is a separate option fromasseton purpose: projects overrideasset( servebase points it atsrc/pug), and an override would have silently taken the new default down with it.ignorednow always includes.git,.DS_Store,Thumbs.db,*.swpand*~, with anything the caller passes appended rather than replacing them. it also reaches the builders' initial scan, which never received it before -opt.watcher.ignoredwas read, and nothing set it. patterns are written**/xso they match both a bare basename and a full path, because chokidar tests one and the initial scan the other.- fix bug: a directory could be treated as a build target. the initial scan recursed
into it and then fell through to
isSupported, which an extension whitelist almost always failed - so it went unnoticed until a builder with no whitelist said yes to every directory it walked. - fix bug: the asset builder claimed outputs it had no source for.
watch.demanduses the first adapter whoseresolveanswers, so withdesdir: staticit would answer for a pug page or a compiled.lsand resolve it to a path that does not exist.resolvenow requires the source to be there. - fix bug: purging a batch stopped at the first file whose copy was already gone, leaving the rest of the batch deployed. a directory removal arrives as one batch.
the build no longer competes with the server it is building for.
- minification runs on a
worker_threadsworker.uglify-jsis synchronous cpu work and srcbuild usually shares a process with a server: measured on a 0.94MB bundle, 2677ms of minify blocked the event loop for 1769ms in one stall. that is long enough for a coldpg.Poolconnect with a 2s timeout to expire while its handshake callbacks cannot be delivered, so the request fails with a database error that has nothing to do with the database. through the worker the same bundle costs ~20% more total time - 9ms of it moving strings across - and the loop's worst tick was 13ms. no size threshold, because cost does not track size: 800KB of one corpus took 88ms and 960KB took 2319ms. the worker spawns on first use, isunref'd, and is terminated after 30s idle; if it cannot start or dies, everything falls back in-process.SRCBUILD_MINIFY_WORKER=0disables it. thelscandstyluspug filters stay synchronous - pug's filter interface has no async form - and they only handle small inline snippets. - fix bug: a minifier error produced nothing, silently.
uglify-js.minifysignals a syntax error by returning{error}with nocodefield; every call site read.codeoff that and gotundefined, then either wrote it as an empty.min.js(lsc, the pug filters ) or joined it into a bundle, where[a, undefined, b] .join('')simply drops it - one source file with a typo and the bundle shipped without that file, no log, no throw, and a complete unminified twin next to it. all minifier calls now go throughsrc/minify.ls, which returns the input unchanged on failure and logs. an unminified asset is bigger, not broken. - a bundle builds one at a time. rebuilds arrive in bursts - fedep touching every lib
file, a save invalidating a shared include - and each request used to start its own
full read + minify. requests that arrive during a build now set a flag instead of
queueing, and the run in flight does one more pass when it finishes, which subsumes
all of them: n requests cost at most two builds.
forceis sticky across the collapse, so a build needed because the source list changed is never swallowed. watcher.readyresolves when every adapter's initial scan has built, including the bundles those builds triggered.adapter.init!returned a promise that every caller discarded, so a host could not tell a running first build from a finished one - and hostslistenbefore theywatch, i.e. they serve requests during the heaviest build of the process's life. it never rejects: one bad source file should not stop a server from starting.stylus' builder returns a promise instead of being a synchronousforloop, which is what lets its initial scan participate inready.
- warn when the injected
lib.pugis not the one shipped with the running srcbuild. it is injected by path and resolved from the frontend root, so whichever copy lands in<base>/node_moduleswins regardless of which srcbuild is running - and a stale one is silent: pages build, nothing errors, and every feature that lives in lib.pug (asseturl,bundleurl,hashfile) is simply absent. observed in the wild: a 2023 copy under a frontend root made content addressing inert while every other check still passed. - test that the shipped lib.pug actually reaches the page - that
asseturlis called during a render and its result lands in the html.
- fix bug: the url -> pages index was memory-only, and it is only filled while a page
renders. a warm start rebuilds nothing, so the index was empty exactly when the first
edit after a restart needed it: the content hash moved and no page was re-rendered to
follow it. it now lives in the manifest (
refsper url ) and is loaded on start. writes are deferred and only happen when a ref is new, so a cold build does not write the manifest once per asset per page. invalidate-urllogs the page count even when it is zero. returning silently is what made the above look like it was working.- a deleted pug file is dropped from the index.
- content addressing is OPT IN:
hash: {enabled: true}. off, nothing changes. it rewrites the url of every generated asset in every page and buys nothing until the edge serves the addressed form with a long max-age, so a project turns it on when it has done that. - two modes.
filenamewrites<name>.<hash>[.min].<ext>next to the output: a url names exactly one byte sequence, so it can be immutable, at the cost of expiring old copies.querypoints at<name>.min.js?v=<hash>instead: nothing accumulates and nothing 404s, but stale html silently gets the current bytes and some CDNs ignore the query when caching. - the plain name is always written and always current in both modes - already deployed html, the pre-first-build fallback, and the nginx try_files target all land on it.
- built files are now content-addressed.
hashstore(.bundle-dep/manifest.json, one per base, shared by every builder ) writes<name>.<hash>[.min].<ext>next to each output and records"<plain url>" -> {url: "<hashed url>", generations}. this covers bundles, compiled.ls(/js/*.js) and compiled.styl(/css/*.css). the plain name keeps being written: it is what already deployed html points at, and the fallback for a page rendered before the first build. the bundle spec name still hashes the url list - that is the spec's identity and the.depfilename - so the content hash is a separate filename segment. asseturl(url, src)andbundleurl({type, name, min, src})are new pug locals, used bylib.pug's+script/+cssand by thebundlefilter. they record which pug file embedded which url, which is how a hash change finds its way back to the pages: a built asset is in no page's pug dependency graph. with a hashed url nolibLoader._vis appended - the filename already moves with the content.- the store announces a url change only when the hash actually moved, so page -> asset -> page settles in one pass instead of looping.
- the manifest is written synchronously before the change is announced, so a render right after a rebuild can never read a manifest that is still behind.
- a builder that skips because its output is fresh now adopts that output into the store, so a wiped manifest heals instead of falling back to the plain url forever.
- block bundles re-resolve their dependencies from the block manager on every build. the set was only ever captured when the declaring pug file was analysed, so a block that gained a dependency did not rebuild when that new dependency changed.
- the express view engine resolves these urls by reading the manifest off disk ( keyed on mtime ), so it works without a store wired in and across processes.
- a spec that loses its last
specsrc( the pug file declaring it was deleted ) now drops its built output and its manifest entry, not just its.dep. - hashed generations are expired by age as well as by count: a generation is deleted
only when it is both beyond
keep( default 3 ) and older thankeepDays( default 30 ). count alone answers the wrong question - three rebuilds can be three hours or three months, while the risk is how long a browser tab stays open. storemay be given as a function, for a host that constructs its express view engine before the builders exist.- fix bug:
specmgr.clear-dirtywas a prototype-leveldebounce, whose timer lives in one closure. with more than one base, one bundler's pending flush was cancelled by another's and its spec changes were silently dropped. - fix bug: a non-minified
packbundle produced<name>..js( double dot ). - fix bug:
adapter.changeenumerated dependency paths instead of visiting nodes. a dependency cycle hung the process, and a fan-in/fan-out graph made the queue grow multiplicatively. dependency mtime is now a separate memoised pass, shared withdirty-check. - fix bug: a file whose
get-dependenciesthrew was dropped entirely - it was never built, and its edges were never recorded, so fixing the included file triggered nothing. failed files are now built anyway ( so the real error is reported ) and retried on every subsequent change event. - fix bug:
specmgr.unlinkcalledSet::remove, andspecmgr.del-specsrccalledunlinkon a spec instead of on the manager. both threw. as a result the reverse index only ever grew: a file bundled once kept triggering that bundle forever. - fix bug:
specmgr.deletenever removed the spec nor its.depcache, soload-cachesresurrected dead specs on the next start. - a deleted pug file now releases the bundle specs it declared.
build-by-specskips when the output is newer than every source, like every other builder. bundles are no longer rewritten on each event and on each restart.- fix bug: a
bundle.jsonchange in the same batch as a source change dropped the source change silently. - fix bug: the
.minfilename was derived with a stringreplace, which hits the first occurrence -three.js/main/index.jsproducedthree.min.js/main/index.js. - fix bug: the pug build's freshness guard only looked at the precompiled view, so a missing static html was not regenerated.
- fix bug: the express view engine constructed a pug builder with the default
initScan, so it ran a second full scan and rebuilt the whole pug tree in parallel with the real builder - whichever finished last won the output. it only needsmapandgetExtapi, so it no longer scans. view/pughonours express'view cachesetting instead of forcing it on.- add a test suite (
npm test, node:test ).
- upgrade i18next-fs-backend to fix vulnerability
- upgrade i18next-fs-backend and other dependencies to fix vulnerability
- use
buildIntloption to toggleintlfolder generation.
- upgrade dependencies for vulnerability fixing
- support customized locals in pug builder
- fix bug: cached source file is not updated - it's mtime is not retrieved because getting desv mtime failure.
- fix bug: precompiled js isn't updated even if src file updated.
- fix bug:
srcbuild-pugtriggers a directory traverse which shouldn't happen. - add option
initScanfor toggling initial directory traverse.
- bundle should add both codesrc and src so the dependencies will be accurate
- use bundler class api for bundled file path if bundler is not provided in pugbuild
- auto set type when loading config if type is not defined
- upgrade @plotdb/block, @plotdb/css and @plotdb/rescope dependencies for bug fixing
- upgrade dependencies
@plotdb/block,@plotdb/rescopeand@plotdb/csscope
- fix bug: bunlder filter should only work if bundler is provided and available
- separate ext/base init into
initAdapterandinitVarsso we can update vars first - bundler ext:
- accept function as manager parameter in bundler.
relativePathis now by default true- tweak error logging for bundling issue
- breaking change: in bundler, path of
configFileshould now be relative tobase. - support block bundling with
bundlefilter - upgrade dependencies
- audit fix vulnerability about dependency
minimatch - enable asset build directly in lsp
- remove logging when view rendering fails since it should be handled by express server
- make error of view rendering fails a lderror with id 1033
- fix bug: bunlder is not added into adapter list in lsp, thus sometimes rebuild wont be triggered.
- fix bug: pack option in css/script should by default use minimized file.
- support
minoption to explicitly use unminimized file with pack option
- fix bug: ext/bundle fails if
relative-pathis false
- fix bug: precompiled pug js should still be run with custom option and api
- support auto packing with limitation.
- fix bug: multiple subtree features doesn't work, because we didn't add all adapters into watcher
- support building of multiple subtree
- support pug generation from outside of src dir
- disable pug
compileDebugoption by default - rebuild demo dir
- in watcher log, show correct watched directory instead of
src - set
_rootwith default value["."]if optionrootis omitted. - force
intlbaseto return absolute path
- support customizable watching directory.
- support asset build ( static file copying )
- support
noViewmode in pugbuild
- support language modifier in
intlbaseAPI
- trap bundle file parsing error and log, instead of crash directly
- fix bug: pug view engine doesn't support
filtersoption
- support custom filter in ext/pug
- bug fix: pug build fails when pug file is empty
- upgrade @loadingio/debounce.js
- tweak dependency range syntax
- audit and fix cached-path-relative vulnerability
- bug fix: crash when iterating to a symlink pointing to a non-existed file.
- use
@plotdb/colorsto replacecolors
- upgrade marked for vulnerability fixing
- support legacy syntax in libLoader for script loading
- fix bug:
libLoader.rootdoesn't work properly
- support relative path in bundle.json
- add test case for bundler
- use local script for testing
- bug fix:
deferin libLoader should be by default true. - bug fix: stylus extension doesn't provide correct path for dependencies.
- bug fix: the
scriptandcssmixin supports should be done bypostParseplugin instead of code modification.
- directly support
scriptandcssmixin in pug compiling.
- bug fix: bundle not rebuild when bundle config file updated
- bug fix: bundler exception not caught
- totally remove
compressoption to prevent unwanted side effect of code removal
- dont compress unused in pug lsc filter for our potential use of custom script block design in @plotdb/block
- remove log
- pass
ignoredto adapter to bypass unnecessary files to save time - by default minimize javascript and css in pug filter.
- set
doctypetohtmlalso inpug-clito preventt="t"generation.
- set
doctypetohtmlto preventt="t"generation.
- add
srcbuild-pugcommand for building pug with extapi - fix yaml loading issue by using
loadinstead ofsafe-load.
- fix module resolving path bug
- resolve module path from basedir in ext/pug.
- bump stylus version to 0.55.0 for removing deprecated dependencies
- fix bug: lsc builder doesn't build unless glslify is enabled
- support
jsonAPI for reading json file in pug
- fix bug: glslify transformed by browserify should have basedir from src file dir.
- upgrade
path-parseto fix vulnerability - support glslify transfomration by option
use-glslify
- add
i18n.intlbaseandi18n.langaugepug api and deprecateintlbasepug api.
- fix bug: incorrect parameter passing in view/pug to ext/pug
- add bundling sample code
- fix bundling file path shown in log
- fix bug:
desdirandbasenot passed to pug in pug view constructor
- fix bug: basedir should be opt.basedir
- support pug view engine for express
- fix bug: trying to get mtime of a non-existed file.
- support options for files to ignore. by default, ignore
.gitfolders.
- simplify log
- trap exception during
log-dependenciesand prevent from further building. - keep old dependency if
log-dependenciesfails.
- support bundling
- fix bug in ext/pug: basedir doesn't exist when initing, causing problem when getting dependencies. use path.resolve(srcdir) instead.
- fix typo
- fix bug: let pug use correct filename and basedir parameter. resolve pug files correctly