From 393ab0b8dfe8ad696575d38309140d7d609cc435 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Mon, 24 Dec 2018 13:54:43 -0800 Subject: [PATCH] Support a static data directory 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. --- .../core/integration-tests/test/server.js | 72 ++++++++++++++++++- packages/core/parcel-bundler/src/Bundler.js | 12 ++++ packages/core/parcel-bundler/src/Server.js | 21 ++++-- packages/core/parcel-bundler/src/cli.js | 5 ++ 4 files changed, 105 insertions(+), 5 deletions(-) diff --git a/packages/core/integration-tests/test/server.js b/packages/core/integration-tests/test/server.js index f5e18b07dab5..f6f7d793cf43 100644 --- a/packages/core/integration-tests/test/server.js +++ b/packages/core/integration-tests/test/server.js @@ -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) { @@ -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: '/' diff --git a/packages/core/parcel-bundler/src/Bundler.js b/packages/core/parcel-bundler/src/Bundler.js index f30ae772a525..ace51b46bf08 100644 --- a/packages/core/parcel-bundler/src/Bundler.js +++ b/packages/core/parcel-bundler/src/Bundler.js @@ -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'), @@ -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: diff --git a/packages/core/parcel-bundler/src/Server.js b/packages/core/parcel-bundler/src/Server.js index 4e9aacda78d5..65e7af9ab7ba 100644 --- a/packages/core/parcel-bundler/src/Server.js +++ b/packages/core/parcel-bundler/src/Server.js @@ -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(); @@ -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(); diff --git a/packages/core/parcel-bundler/src/cli.js b/packages/core/parcel-bundler/src/cli.js index 0ecb014fedb5..82b1dc207713 100755 --- a/packages/core/parcel-bundler/src/cli.js +++ b/packages/core/parcel-bundler/src/cli.js @@ -66,6 +66,11 @@ program /^([0-5])$/ ) .option('--cache-dir ', 'set the cache directory. defaults to ".cache"') + .option('--static-data-dir ', 'serve as static data') + .option( + '--static-data-url ', + 'serve the static data at this http path on the dev server, defaults to the directory name of --static-data-dir' + ) .action(bundle); program