Installation
git clone
cd nollup-test-case-output-dir
yarn
Usage
Run tests:
yarn zoar
Watch test:
yarn zoar -w
In interactive watch:
- press
Enter
to rerun - enter
ib
to run with node debugger
Run tests with debug output:
CUSTOM=0 yarn zoar
The custom report format is most informative for debug. Its layout is as follow:
1. Test-specific Nollup options (passed to dev middleware)
2. Test-specific Rollup config
3. Rollup:
file writting by Rollup => URL used by the test to try to get the file
4. Nollup:
dump of `Object.keys(files)` in dev middleware (only with custom branch)
Example:
1. { contentBase: 'dist' }
2. { input: 'src/main.js', output: { dir: 'dist/app', format: 'es' } }
3. Rollup:
⚠ 'dist/app/main.js' => /app/main.js
⚠ 'dist/app/nested-93659157.js' => /app/nested-[hash].js
⚠ 'dist/app/nested-d1b6ea0f.js' => /app/nested-[hash].js
4. Nollup:
[ 'main.js', 'nested-[hash].js' ]
Principle
The test principle is to run Rollup with the given config, and observe the files that are written to disk by Nollup. Then, it fires the Nollup middleware, and tries to access each file by URL, like if from a web server from dist
folder.
Both entry point files and code splitted (dynamic imports) chunks appears in Rollup's output, and so they are tested for simplicity, but I think we only really care about the entry points actually.
NOTE I have been working on a Nollup branch to explore integration with Sapper (Svelte's official app generator). The branch includes a custom onBundle
option that is used by the test to observe Nollup's output. In normal Nollup, this hook is not present, so the test won't display the files as seen by Nollup.
Issues
There are 2 classes of problems:
-
misalignment with Rollup for filenames of output files
-
it is hard or impossible to have Nollup serves bundle files at the same URL that we'd get with Rollup + web server, in some cases
output.dir
Directory path is lost with When using a nested output.dir
, Rollup keeps the full directroy path when writting entry points, but Nollup only keeps the basename.
And so, while the file would be accessible at URL /app/main.js
with a web server and Rollup, it is accessible at URL /main.js
in Nollup.
=== output.dir: nested main.js =================================================
{ contentBase: 'dist' }
{
input: 'src/main.js',
inlineDynamicImports: true,
output: { dir: 'dist/app', format: 'es' }
}
Rollup:
⚠ 'dist/app/main.js' => /app/main.js
Nollup:
[ 'main.js', 'nested-[hash].js' ]
Expected: app/main.js
instead of main.js
Entry points with same basename (in different dirs) conflict
When 2 entry points have the same basename, Rollup adds an ordinal suffix, but Nollup mashes them together.
=== output.dir: entrypoints conflict ===========================================
{ contentBase: 'dist' }
{
input: [ 'src/a/main.js', 'src/a/b/main.js' ],
output: { dir: 'dist/app', format: 'es' }
}
Rollup:
⚠ 'dist/app/main.js' => /app/main.js
⚠ 'dist/app/main2.js' => /app/main2.js
Nollup:
[ 'main.js' ]
Expected: [ 'app/main.js', 'app/main2.js' ]
Dynamic chunks with same basename conflict
Same with dynamic chunks: they get mashed together when they share the same basename.
=== output.dir: chunk conflict =================================================
{ contentBase: 'dist' }
{
input: [ 'src/main.js', 'src/second.js' ],
output: { dir: 'dist/app', format: 'es' }
}
Rollup:
⚠ 'dist/app/main.js' => /app/main.js
⚠ 'dist/app/second.js' => /app/second.js
⚠ 'dist/app/nested-3f8ba19f.js' => /app/nested-[hash].js
⚠ 'dist/app/nested-93659157.js' => /app/nested-[hash].js
Nollup:
[ 'main.js', 'second.js', 'nested-[hash].js' ]
Expected: [ ..., 'nested-[hash].js', 'nested2-[hash].js' ]
(or just anything that prevents them from having the same name an shadowing each other)
Also without hash:
=== output.dir: chunk conflict without hashes ==================================
{ contentBase: 'public', baseUrl: 'dist' }
{
input: [ 'src/main.js', 'src/second.js' ],
output: { dir: 'dist/app', format: 'es', chunkFileNames: '[name].js' }
}
Rollup:
⚠ 'dist/app/main.js' => /app/main.js
⚠ 'dist/app/second.js' => /app/second.js
⚠ 'dist/app/nested.js' => /app/nested.js
⚠ 'dist/app/nested2.js' => /app/nested2.js
Nollup:
[ 'main.js', 'second.js', 'nested.js' ]
Expected: [ ..., 'nested.js', 'nested2.js' ]
Public directory
Problem: once we preserve the output.dir
in the generated output file names to align with Rollup, then we also get the "public" directory in the URL generated by Nollup (e.g. dist/app/main.js
). However, with Rollup + Webserver, a part of output.dir
(e.g. dist/
) would be the web root directory, and so it wouldn't appear in the URL of the file (e.g. /app/main.js
).
public directory same as dist
When the public directory is the same as the output dir, we can derive the URL suffix we need to drop from contentBase
and output.dir
.
const baseUrl = output.dir.startsWith(options.contentBase)
? output.dir.slice(options.contentBase.length)
: output.dir // actually in this case, I think the file should not be served?
=== public dir: serve static from /dist, build to /dist ====================
{ contentBase: 'dist' }
{ input: 'src/a/main.js', output: { dir: 'dist/app', format: 'es' } }
Rollup:
⚠ 'dist/app/main.js' => /app/main.js
Nollup:
[ 'main.js' ]
Expected: [ 'app/main.js' ]
public directory different from dist
When the user's setup directory layout differs between prod and dev (e.g. copying static assets in prod, but serving them from source in dev), then the part of output.dir
that must be trimmed to form the URL must be provided by the user.
=== public dir: serve static from /public, build to /dist ======================
{ contentBase: 'public', baseUrl: 'dist' }
{ input: 'src/a/main.js', output: { dir: 'dist/app', format: 'es' } }
Rollup:
⚠ 'dist/app/main.js' => /app/main.js
Nollup:
[ 'main.js' ]
Expected: [ 'app/main.js' ]
Exploratory work
The sapper
branch of my Nollup fork passes all the above test by adding an ordinal suffix to entry / chunk names, joining output.dir
to produce a file URL, and adding a baseUrl
option to drop part of the output dir from the URL.
yarn add -D rixo/nollup#sapper
yarn zoar