Skip to content

Commit

Permalink
Support a static data directory
Browse files Browse the repository at this point in the history
This is my take on the need to serve static data from the dev server.
Anything served from this path will be served as raw as possible, with
404s for missing files, and no index file.
  • Loading branch information
magcius committed Feb 19, 2019
1 parent 31bd420 commit 393ab0b
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 5 deletions.
72 changes: 71 additions & 1 deletion packages/core/integration-tests/test/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ const sinon = require('sinon');

describe('server', function() {
let server;
afterEach(function() {
afterEach(async function() {
if (server) {
server.close();
server = null;
}

await fs.rimraf(path.join(__dirname, 'data'));
});

function get(file, client = http) {
Expand Down Expand Up @@ -230,6 +232,74 @@ describe('server', function() {
);
});

it('should serve paths from the static data directory', async function() {
let b = bundler(path.join(__dirname, '/integration/html/index.html'), {
staticDataDir: path.join(__dirname, 'data')
});
server = await b.serve(0);

// When accessing /data/hello.txt we should get txt document.
await fs.mkdirp(path.join(__dirname, '/data'));
await fs.writeFile(path.join(__dirname, '/data/hello.txt'), 'hello');
let data = await get('/data/hello.txt');
assert.equal(data, 'hello');

// When accessing non-existent thing in static dir we should get 404
let threw = false;
try {
await get('/data/nope.txt');
} catch (err) {
threw = true;
}

assert(threw);

// When accessing non-existent thing in regular we should get index
data = await get('/data.js');
assert.equal(
data,
await fs.readFile(path.join(__dirname, '/dist/index.html'), 'utf8')
);
});

it('should serve paths from the static data directory with a custom url', async function() {
let b = bundler(path.join(__dirname, '/integration/html/index.html'), {
staticDataDir: path.join(__dirname, 'data'),
staticDataURL: '/static/'
});
server = await b.serve(0);

// When accessing /data/hello.txt we should get txt document.
await fs.mkdirp(path.join(__dirname, '/data'));
await fs.writeFile(path.join(__dirname, '/data/hello.txt'), 'hello');
let data = await get('/static/hello.txt');
assert.equal(data, 'hello');

// When accessing non-existent thing in static dir we should get 404
let threw = false;
try {
await get('/static/nope.txt');
} catch (err) {
threw = true;
}

assert(threw);

// When accessing non-existent thing in dist dir we should get index
data = await get('/static.js');
assert.equal(
data,
await fs.readFile(path.join(__dirname, '/dist/index.html'), 'utf8')
);

// When accessing non-existent thing in not our path we should get index
data = await get('/data/hello.txt');
assert.equal(
data,
await fs.readFile(path.join(__dirname, '/dist/index.html'), 'utf8')
);
});

it('should not log dev server access for log level <= 3', async function() {
let b = bundler(path.join(__dirname, '/integration/html/index.html'), {
publicUrl: '/'
Expand Down
12 changes: 12 additions & 0 deletions packages/core/parcel-bundler/src/Bundler.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,16 @@ class Bundler extends EventEmitter {
: watch;
const scopeHoist =
options.scopeHoist !== undefined ? options.scopeHoist : false;
const staticDataDir =
typeof options.staticDataDir === 'string'
? Path.resolve(options.staticDataDir)
: null;
const staticDataURL =
options.staticDataUrl ||
options.staticDataURL ||
(staticDataDir !== null
? '/' + Path.basename(options.staticDataDir)
: null);
return {
production: isProduction,
outDir: Path.resolve(options.outDir || 'dist'),
Expand All @@ -117,6 +127,8 @@ class Bundler extends EventEmitter {
watch: watch,
cache: typeof options.cache === 'boolean' ? options.cache : true,
cacheDir: Path.resolve(options.cacheDir || '.cache'),
staticDataDir: staticDataDir,
staticDataURL: staticDataURL,
killWorkers:
typeof options.killWorkers === 'boolean' ? options.killWorkers : true,
minify:
Expand Down
21 changes: 17 additions & 4 deletions packages/core/parcel-bundler/src/Server.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ function middleware(bundler) {
dotfiles: 'allow'
});

let serveStaticDataDir = null,
staticDataURL = null;
if (bundler.options.staticDataDir) {
serveStaticDataDir = serveStatic(bundler.options.staticDataDir, {
index: false,
redirect: false,
setHeaders: setHeaders
});
staticDataURL = bundler.options.staticDataURL;
if (!staticDataURL.endsWith('/')) staticDataURL += '/';
}

return function(req, res, next) {
logAccessIfVerbose();

Expand All @@ -54,10 +66,11 @@ function middleware(bundler) {
let {pathname} = url.parse(req.url);
if (bundler.error) {
return send500(bundler.error);
} else if (
!pathname.startsWith(bundler.options.publicURL) ||
path.extname(pathname) === ''
) {
} else if (staticDataURL !== null && pathname.startsWith(staticDataURL)) {
// If the URL is in the static data path, then serve it directly.
req.url = pathname.slice(staticDataURL.length);
return serveStaticDataDir(req, res, send404);
} else if (!pathname.startsWith(bundler.options.publicURL)) {
// If the URL doesn't start with the public path, or the URL doesn't
// have a file extension, send the main HTML bundle.
return sendIndex();
Expand Down
5 changes: 5 additions & 0 deletions packages/core/parcel-bundler/src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ program
/^([0-5])$/
)
.option('--cache-dir <path>', 'set the cache directory. defaults to ".cache"')
.option('--static-data-dir <path>', 'serve <path> as static data')
.option(
'--static-data-url <path>',
'serve the static data at this http path on the dev server, defaults to the directory name of --static-data-dir'
)
.action(bundle);

program
Expand Down

0 comments on commit 393ab0b

Please sign in to comment.