From 8c221e30f5da9c7d0b61382cbfbd3e978d69cedc Mon Sep 17 00:00:00 2001 From: "Kent C. Dodds" Date: Wed, 31 Aug 2016 15:27:11 -0600 Subject: [PATCH] fix(umd): do umd manually Rollup is not capable of exposing a default export AND a named export as a UMD module in a useful way for the global context. So this adds some custom UMD logic to the bottom of the main file. This should hopefully never need to be touched, but there are tests that validate the CJS and ES6 module exports. Things will be challenging when people want to use native ES6 modules with this module (because now we're not exposing this as a native ES6 module). But we weren't really doing that in the first place (we were transpiling) so that's fine for now. Fixes #14 --- dist-test/index.js | 65 ++++++++++++++++++++++++++++++++++++++++++++++ package-scripts.js | 32 ++++++++++++++++++++++- package.json | 7 +++-- rollup.config.js | 4 +-- src/index.js | 15 +++++++++-- src/index.test.js | 3 ++- 6 files changed, 117 insertions(+), 9 deletions(-) create mode 100644 dist-test/index.js diff --git a/dist-test/index.js b/dist-test/index.js new file mode 100644 index 0000000..17007c5 --- /dev/null +++ b/dist-test/index.js @@ -0,0 +1,65 @@ +/* eslint import/default:0, import/named:0, import/no-unresolved:0, import/extensions:0, no-console:0 */ +/* + * This file is here to validate that the built version of the library exposes the module in the way that we + * want it to. Specifically that the ES6 module import can get the matchSorter function via default import and the + * rankings via named import. Also that the CommonJS require returns the matchSorter function (rather than an object + * that has the matchSorter as a `default` property). + * + * This file is unable to validate the AMD or global exports. + */ +import assert from 'assert' + +import cjsImport, {rankings as cjsRankings} from '../dist/cjs' +import umdImport, {rankings as umdRankings} from '../dist/umd/match-sorter' + +const cjsRequire = require('../dist/cjs') +const umdRequire = require('../dist/umd/match-sorter') + + +assert( + isMatchSorterFunction(cjsImport) && isRankingsObject(cjsRankings), + 'CJS build has a problem with ES6 modules' +) + +assert( + isMatchSorterFunction(cjsRequire), + 'CJS build has a problem with CJS' +) + +assert( + isMatchSorterFunction(umdImport) && isRankingsObject(umdRankings), + 'UMD build has a problem with ES6 modules' +) + +assert( + isMatchSorterFunction(umdRequire), + 'UMD build has a problem with CJS' +) + +// TODO: how could we validate the AMD/global modules? + +console.log('Built modules look good 👍') + +function isMatchSorterFunction(thing) { + if (typeof thing !== 'function') { + console.error(`matchSorter thing should be a function. It's a ${typeof thing}`) + return false + } + if (thing.name !== 'matchSorter') { + console.error(`the function is not called "matchSorter". It's called ${thing.name}`) + return false + } + return isRankingsObject(thing.rankings) +} + +function isRankingsObject(thing) { + if (typeof thing !== 'object') { + console.error(`rankings object thing should be an object. It's a ${typeof thing}`) + return false + } + if (!Object.keys(thing).includes('NO_MATCH')) { + console.error(`rankings object should include a NO_MATCH key. It only has ${Object.keys(thing)}`) + return false + } + return true +} diff --git a/package-scripts.js b/package-scripts.js index f700e3f..2cdcf8b 100644 --- a/package-scripts.js +++ b/package-scripts.js @@ -13,6 +13,14 @@ module.exports = { description: 'Run AVA in watch mode', script: 'ava -w --require babel-register', }, + build: { + description: 'validates the built files', + script: 'babel-node dist-test/index.js', + watch: { + description: 'watches the dist directory for changes and reruns test.build when it changes', + script: watch(['dist-test/**/*.js', 'dist/**/*.js'], 'npm start -s test.build'), + }, + }, }, build: { description: 'delete the dist directory and run all builds', @@ -29,6 +37,20 @@ module.exports = { script: 'cross-env MINIFY=true rollup --config --sourcemap', }, }, + watch: { + description: 'watches the filesystem for changes and reruns the build when changes have been made', + script: watchSrc('npm start -s build'), + }, + }, + dev: { + build: { + description: 'helps while working on the module build and tests', + script: 'p-s -p build.watch,test.build.watch', + }, + coverage: { + description: 'runs tests as files change in `src`', + script: watchSrc('p-s test'), + }, }, lint: { description: 'lint the entire project', @@ -44,7 +66,7 @@ module.exports = { }, validate: { description: 'This runs several scripts to make sure things look good before committing or on clean install', - script: 'p-s -p lint,build,test', + script: 'p-s -p lint,build,test && p-s test.build', }, addContributor: { description: 'When new people contribute to the project, run this', @@ -59,3 +81,11 @@ module.exports = { silent: false, }, } + +function watch(paths, command) { + return `nodemon --quiet ${paths.map(p => `--watch ${p}`).join(' ')} --exec "${command}"` +} + +function watchSrc(command) { + return watch(['src/**/*.js'], command) +} diff --git a/package.json b/package.json index 01ca284..c98fcf5 100644 --- a/package.json +++ b/package.json @@ -14,10 +14,12 @@ "author": "Kent C. Dodds (http://kentcdodds.com/)", "license": "MIT", "bundledDependencies": [ - "diacritic" + "diacritic", + "global-object" ], "dependencies": { - "diacritic": "0.0.2" + "diacritic": "0.0.2", + "global-object": "1.0.0" }, "devDependencies": { "all-contributors-cli": "^3.0.0", @@ -34,6 +36,7 @@ "eslint": "^3.1.1", "eslint-config-kentcdodds": "^10.0.1", "ghooks": "^1.3.2", + "nodemon": "1.10.2", "nyc": "8.1.0", "opt-cli": "^1.4.2", "p-s": "^2.3.0", diff --git a/rollup.config.js b/rollup.config.js index 0495544..0496023 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -10,13 +10,11 @@ const filename = process.env.MINIFY ? 'match-sorter.min.js' : 'match-sorter.js' export default { entry: 'src/index.js', dest: `dist/umd/${filename}`, - format: 'umd', - moduleName: 'matchSorter', + exports: 'none', plugins: [ nodeResolve({jsnext: true, main: true}), commonjs({include: 'node_modules/**'}), rollupBabel({exclude: 'node_modules/**'}), process.env.MINIFY ? uglify() : null, ].filter(i => !!i), - exports: 'named', } diff --git a/src/index.js b/src/index.js index f903fa3..829390f 100644 --- a/src/index.js +++ b/src/index.js @@ -5,6 +5,7 @@ * @author Kent C. Dodds */ import diacritics from 'diacritic' +import globalObject from 'global-object' const rankings = { EQUAL: 6, @@ -17,7 +18,6 @@ const rankings = { } matchSorter.rankings = rankings -export {matchSorter as default, rankings} /** * Takes an array of items and a value and returns a new array with the items that match the given value @@ -227,4 +227,15 @@ function getAllValuesToRank(item, keys) { return keys.reduce((allVals, key) => allVals.concat(getItemValue(item, key)), []) } -module.exports = exports.default // CommonJS compat +// some manual ✨ magic umd ✨ here because Rollup isn't capable of exposing our module the way we want +// see dist-test/index.js +/* istanbul ignore next */ +if (typeof exports === 'object' && typeof module !== 'undefined') { + matchSorter.default = matchSorter + Object.defineProperty(exports, '__esModule', {value: true}) + module.exports = matchSorter +} else if (typeof define === 'function' && define.amd) { // eslint-disable-line + define(() => matchSorter) // eslint-disable-line +} else { + globalObject.matchSorter = matchSorter // eslint-disable-line +} diff --git a/src/index.test.js b/src/index.test.js index 76d5c5e..775dafb 100644 --- a/src/index.test.js +++ b/src/index.test.js @@ -1,6 +1,7 @@ /* eslint ava/no-only-test:0, ava/no-skip-test:0 */ import test from 'ava' -import matchSorter, {rankings} from './' +// have to disable eslint for the next line because we have to do weird things to make things work with UMD +import matchSorter, {rankings} from './' // eslint-disable-line import/default,import/named const tests = { 'returns an empty array with a string that is too long': {