Skip to content

Commit

Permalink
feat!: Set package.json#exports
Browse files Browse the repository at this point in the history
  • Loading branch information
coreyfarrell committed Mar 11, 2020
1 parent adce922 commit f72bc51
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 61 deletions.
5 changes: 5 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"ignorePatterns": [
"fixtures/**"
]
}
3 changes: 2 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
*.tgz
coverage
.nyc_output
nyc.config.js
.eslintrc.json
nyc.config.cjs
package
.travis.yml
fixtures
Expand Down
32 changes: 16 additions & 16 deletions index.js → index.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,36 @@ const fp = require('fastify-plugin');
const babel = require('@babel/core');
const hasha = require('hasha');

function shouldBabel(reply, opts) {
return opts.babelTypes.test(reply.getHeader('Content-Type') || '');
function shouldBabel(reply, options) {
return options.babelTypes.test(reply.getHeader('Content-Type') || '');
}

function babelPlugin(fastify, opts, next) {
if (!opts.babelTypes) {
opts.babelTypes = /(?:java|ecma)script/;
function babelPlugin(fastify, options, next) {
if (!options.babelTypes) {
options.babelTypes = /(?:java|ecma)script/u;
}

const cacheSalt = opts.cacheHashSalt ? hasha(opts.cacheHashSalt, {algorithm: 'sha256'}) : '';
const cacheSalt = options.cacheHashSalt ? hasha(options.cacheHashSalt, {algorithm: 'sha256'}) : '';

fastify.addHook('onSend', babelOnSend);

next();

function actualSend(payload, next, hash, filename) {
const babelOpts = {
...opts.babelrc,
const babelOptions = {
...options.babelrc,
filename: filename || path.join(process.cwd(), 'index.js')
};

try {
const {code} = babel.transform(payload, babelOpts);
const {code} = babel.transform(payload, babelOptions);
if (hash) {
opts.cache.set(hash, code);
options.cache.set(hash, code);
}

next(null, code);
} catch (error) {
if (opts.maskError !== false) {
if (options.maskError !== false) {
error.message = 'Babel Internal Error';
try {
error.message = `Babel Transform error ${error.code} at line ${error.loc.line}, column ${error.loc.column}.`;
Expand All @@ -46,12 +46,12 @@ function babelPlugin(fastify, opts, next) {
}
}

function babelOnSend(req, reply, payload, next) {
if (req.headers['x-no-babel'] !== undefined) {
function babelOnSend(requests, reply, payload, next) {
if (requests.headers['x-no-babel'] !== undefined) {
return next();
}

if (!shouldBabel(reply, opts)) {
if (!shouldBabel(reply, options)) {
return next();
}

Expand All @@ -67,14 +67,14 @@ function babelPlugin(fastify, opts, next) {
}

let hash;
if (opts.cache) {
if (options.cache) {
const cacheTag = reply.getHeader('etag') || reply.getHeader('last-modified');
/* If we don't have etag or last-modified assume this is dynamic and not worth caching */
if (cacheTag) {
/* Prefer payload.filename, then payload it is a string */
const filename = typeof payload === 'string' ? payload : payload.filename;
hash = hasha([cacheTag, filename, cacheSalt], {algorithm: 'sha256'});
const result = opts.cache.get(hash);
const result = options.cache.get(hash);

if (typeof result !== 'undefined') {
next(null, result);
Expand Down
File renamed without changes.
16 changes: 7 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
"name": "fastify-babel",
"version": "1.3.0",
"description": "Fastify Babel plugin for development servers",
"main": "index.cjs",
"exports": "./index.cjs",
"scripts": {
"release": "standard-version --sign",
"pretest": "xo",
"test": "nyc node test/test.js"
"pretest": "cfware-lint .",
"test": "nyc node test/test.cjs"
},
"engines": {
"node": ">=10"
Expand Down Expand Up @@ -33,6 +35,7 @@
},
"devDependencies": {
"@babel/core": "^7.5.5",
"@cfware/lint": "^1.0.0",
"@cfware/nyc": "^0.6.0",
"babel-plugin-bare-import-rewrite": "^2.0.0",
"fastify": "^2.7.1",
Expand All @@ -41,13 +44,8 @@
"node-fetch": "^2.6.0",
"nyc": "^15.0.0",
"quick-lru": "^5.0.0",
"semver": "^7.1.3",
"standard-version": "^7.0.0",
"string-to-stream": "^3.0.0",
"xo": "^0.26.0"
},
"xo": {
"ignores": [
"fixtures/**"
]
"string-to-stream": "^3.0.0"
}
}
79 changes: 44 additions & 35 deletions test/test.js → test/test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const t = require('libtap');
const fetch = require('node-fetch');
const sts = require('string-to-stream');
const QuickLRU = require('quick-lru');
const semver = require('semver');
const fastifyModule = require('fastify');
const fastifyStatic = require('fastify-static');
const fastifyBabel = require('..');
Expand All @@ -18,7 +19,7 @@ const fromModuleResult = `import fastify from "../fastify/${fastifyPackage.main}

const test = (name, helper, ...args) => t.test(name, t => helper(t, ...args));

const appOpts = {
const appOptions = {
root: path.join(__dirname, '..', 'fixtures'),
prefix: '/'
};
Expand Down Expand Up @@ -54,28 +55,28 @@ const plugins = [
async function createServer(t, babelTypes, maskError, babelrc = {plugins}) {
/* Use of babel-plugin-bare-import-rewrite ensures fastify-babel does the
* right thing with payload.filename. */
const babelOpts = {babelrc, babelTypes, maskError};
const babelOptions = {babelrc, babelTypes, maskError};
const fastify = fastifyModule();

fastify
.get('/undefined.js', (req, reply) => reply.send())
.get('/null.js', (req, reply) => {
.get('/undefined.js', (request, reply) => reply.send())
.get('/null.js', (request, reply) => {
reply.header('content-type', 'text/javascript');
reply.send(null);
})
.get('/nofile.js', (req, reply) => {
.get('/nofile.js', (request, reply) => {
reply.header('content-type', 'text/ecmascript');
reply.send(staticContent);
})
.get(`/${fromModuleSource}`, (req, reply) => {
.get(`/${fromModuleSource}`, (request, reply) => {
const payload = sts(staticContent);
payload.filename = path.resolve(__dirname, '..', fromModuleSource);

reply.header('content-type', 'text/javascript');
reply.send(payload);
})
.register(fastifyStatic, appOpts)
.register(fastifyBabel, babelOpts);
.register(fastifyStatic, appOptions)
.register(fastifyBabel, babelOptions);

await fastify.listen(0);
fastify.server.unref();
Expand All @@ -90,16 +91,16 @@ async function runTest(t, url, expected, {noBabel, babelTypes, babelrc, maskErro
options.headers = {'x-no-babel': 1};
}

const res = await fetch(host + url, options);
const body = await res.text();
const response = await fetch(host + url, options);
const body = await response.text();

t.equal(body.replace(/\r\n/, '\n'), expected);
t.equal(body.replace(/\r\n/u, '\n'), expected);
}

test('static app js', runTest, '/import.js', babelResult);
test('static app js with x-no-babel', runTest, '/import.js', staticContent, {noBabel: true});
test('static app txt', runTest, '/test.txt', staticContent);
test('static app txt with custom babelTypes regex', runTest, '/test.txt', babelResult, {babelTypes: /text/});
test('static app txt with custom babelTypes regex', runTest, '/test.txt', babelResult, {babelTypes: /text/u});
test('dynamic undefined js', runTest, '/undefined.js', '');
test('dynamic null js', runTest, '/null.js', '');
test('dynamic js without filename', runTest, '/nofile.js', babelResult);
Expand All @@ -110,14 +111,14 @@ test('don\'t hide error details', runTest, '/import.js', JSON.stringify(unmasked

test('static app js caching', async t => {
const host = await createServer(t);
const res1 = await fetch(host + '/import.js');
const res2 = await fetch(host + '/import.js', {
const response1 = await fetch(`${host}/import.js`);
const response2 = await fetch(`${host}/import.js`, {
headers: {
'If-None-Match': res1.headers.get('etag')
'If-None-Match': response1.headers.get('etag')
}
});

t.equal(res2.status, 304);
t.equal(response2.status, 304);
});

async function testCache(t, cacheHashSalt) {
Expand All @@ -133,16 +134,16 @@ async function testCache(t, cacheHashSalt) {
const fastify = fastifyModule();
const cache = new QuickLRU({maxSize: 50});
fastify
.get('/nofile.js', (req, reply) => {
.get('/nofile.js', (request, reply) => {
reply.header('content-type', 'text/ecmascript');
reply.header('last-modified', 'Mon, 12 Aug 2019 12:00:00 GMT');
reply.send(staticContent);
})
.get('/uncachable.js', (req, reply) => {
.get('/uncachable.js', (request, reply) => {
reply.header('content-type', 'text/ecmascript');
reply.send(staticContent);
})
.register(fastifyStatic, appOpts)
.register(fastifyStatic, appOptions)
.register(fastifyBabel, {
babelrc: {
plugins: [
Expand All @@ -155,39 +156,39 @@ async function testCache(t, cacheHashSalt) {
});
await fastify.listen(0);
const host = `http://127.0.0.1:${fastify.server.address().port}`;
const doFetch = async (path, step, prevKeys) => {
const res = await fetch(host + path);
const body = await res.text();
const doFetch = async (path, step, previousKeys) => {
const response = await fetch(host + path);
const body = await response.text();
t.equal(body, babelResult);
t.equal(hits, prevKeys ? 2 : step);
t.equal(hits, previousKeys ? 2 : step);
const keys = [...cache.keys()];
if (prevKeys) {
t.same(keys, prevKeys);
if (previousKeys) {
t.same(keys, previousKeys);
} else {
t.equal(keys.length, step);
}

return keys;
};

const doUncachable = async (prevKeys, step) => {
const res = await fetch(host + '/uncachable.js');
const body = await res.text();
const doUncachable = async (previousKeys, step) => {
const response = await fetch(`${host}/uncachable.js`);
const body = await response.text();
t.equal(body, babelResult);
t.equal(hits, step);
t.same([...cache.keys()], prevKeys);
t.same([...cache.keys()], previousKeys);
};

const iter = async prevKeys => {
let keys = await doFetch('/import.js', 1, prevKeys);
if (prevKeys) {
t.same(prevKeys, keys);
const iter = async previousKeys => {
let keys = await doFetch('/import.js', 1, previousKeys);
if (previousKeys) {
t.same(previousKeys, keys);
}

const [importKey] = prevKeys || keys;
const [importKey] = previousKeys || keys;
t.equal(cache.get(importKey), babelResult);

keys = await doFetch('/nofile.js', 2, prevKeys);
keys = await doFetch('/nofile.js', 2, previousKeys);
const [nofileKey] = keys.filter(key => key !== importKey);
t.equal(cache.get(nofileKey), babelResult);

Expand All @@ -212,3 +213,11 @@ test('caching', async t => {
const saltedKey = await testCache(t, 'salt the hash');
t.notSame(key, saltedKey);
});

if (semver.gte(process.versions.node, '13.10.0')) {
test('test exports', async t => {
const selfRef = require('fastify-babel');

t.equal(fastifyBabel, selfRef);
});
}

0 comments on commit f72bc51

Please sign in to comment.