diff --git a/packages/create-universal-package/bin/build.js b/packages/create-universal-package/bin/build.js index 59a89f1..394f165 100755 --- a/packages/create-universal-package/bin/build.js +++ b/packages/create-universal-package/bin/build.js @@ -6,6 +6,11 @@ args .option('skip-preflight', 'Skip preflight check', false) .option('skip-flow', 'Skip generation of flow libdef', false) .option('force-flow', 'Force generation of flow libdef', false) + .option( + 'separate-entries', + 'Use src/index.browser.js and src/index.node.js instead of src/index.js', + false, + ) .option('tests', 'Build tests', false) .option('tests-only', 'Build test bundles only', false); diff --git a/packages/create-universal-package/lib/build.js b/packages/create-universal-package/lib/build.js index 549b602..dcc211a 100644 --- a/packages/create-universal-package/lib/build.js +++ b/packages/create-universal-package/lib/build.js @@ -17,15 +17,28 @@ function build(opts, variants = {}, preflight) { exposedMethods: ['build', 'preflight', 'buildBrowser', 'genFlowLibdef'], }); - const inputOptions = { + const baseInputOptions = { input: path.join(opts.dir, 'src/index.js'), pureExternalModules: true, }; - - const userBabelConfig = validateConfig(opts.dir); + const browserInputOptions = { + ...baseInputOptions, + }; + const nodeInputOptions = { + ...baseInputOptions, + }; const generateFlowLibdef = - !opts.skipFlow && (opts.forceFlow || hasFlowConfig(opts.dir)); + !opts.separateEntries && + !opts.skipFlow && + (opts.forceFlow || hasFlowConfig(opts.dir)); + + if (opts.separateEntries) { + browserInputOptions.input = path.join(opts.dir, 'src/index.browser.js'); + nodeInputOptions.input = path.join(opts.dir, 'src/index.node.js'); + } + + const userBabelConfig = validateConfig(opts.dir); let jobs = []; @@ -62,7 +75,7 @@ function build(opts, variants = {}, preflight) { variants.node && { name: 'build:node', args: [ - inputOptions, + nodeInputOptions, getBabelConfig({env: 'node', target: '8.9.0', userBabelConfig}), [ { @@ -81,7 +94,7 @@ function build(opts, variants = {}, preflight) { variants.browser && { name: 'build:browser (es5)', args: [ - inputOptions, + browserInputOptions, getBabelConfig({ env: 'browser', target: '5', @@ -105,7 +118,7 @@ function build(opts, variants = {}, preflight) { variants.browser && { name: 'build:browser (es2015)', args: [ - inputOptions, + browserInputOptions, getBabelConfig({ env: 'browser', target: '2015', @@ -124,7 +137,7 @@ function build(opts, variants = {}, preflight) { variants.browser && { name: 'build:browser (es2017)', args: [ - inputOptions, + browserInputOptions, getBabelConfig({env: 'browser', target: '2017', userBabelConfig}), [ { diff --git a/packages/create-universal-package/package.json b/packages/create-universal-package/package.json index bec6b55..bf5f32b 100644 --- a/packages/create-universal-package/package.json +++ b/packages/create-universal-package/package.json @@ -14,7 +14,7 @@ "cup-clean": "./bin/clean.js" }, "scripts": { - "test": "echo TODO tests", + "test": "node test/index.js", "lint": "eslint {lib,bin}" }, "dependencies": { diff --git a/packages/create-universal-package/test/index.js b/packages/create-universal-package/test/index.js new file mode 100644 index 0000000..4ccc557 --- /dev/null +++ b/packages/create-universal-package/test/index.js @@ -0,0 +1,62 @@ +const path = require('path'); +const tape = require('tape'); +const {promisify} = require('util'); +const cp = require('child_process'); +const fs = require('fs'); +const exec = promisify(cp.exec); + +tape('fixture package transpile', async t => { + const dir = path.join(__dirname, '../../fixture-package/'); + await exec(`yarn build`, {cwd: dir}); + const expectedFiles = [ + 'browser.es2015.es.js', + 'browser.es2017.es.js', + 'browser.es5.es.js', + 'browser.es5.js', + 'index.es.js', + 'index.js', + 'index.js.map', + 'browser.es2015.es.js.map', + 'browser.es2017.es.js.map', + 'browser.es5.es.js.map', + 'browser.es5.js.map', + 'index.es.js.map', + 'index.js.flow', + ]; + expectedFiles + .map(file => path.join(dir, 'dist', file)) + .forEach((file, index) => { + t.ok(fs.existsSync(file), `${expectedFiles[index]} exists`); + }); + t.end(); +}); + +tape('fixture package separate indexes transpile', async t => { + const dir = path.join(__dirname, '../../fixture-package-separate-indexes/'); + await exec(`yarn build`, {cwd: dir}); + const expectedFiles = [ + 'browser.es2015.es.js', + 'browser.es2017.es.js', + 'browser.es5.es.js', + 'browser.es5.js', + 'index.es.js', + 'index.js', + 'index.js.map', + 'browser.es2015.es.js.map', + 'browser.es2017.es.js.map', + 'browser.es5.es.js.map', + 'browser.es5.js.map', + 'index.es.js.map', + ]; + expectedFiles + .map(file => path.join(dir, 'dist', file)) + .forEach((file, index) => { + t.ok(fs.existsSync(file), `${expectedFiles[index]} exists`); + }); + + t.notok( + fs.existsSync(path.join(dir, 'index.js.flow')), + 'does not generate flow when using separate entries', + ); + t.end(); +}); diff --git a/packages/fixture-package-separate-indexes/.cuprc.js b/packages/fixture-package-separate-indexes/.cuprc.js new file mode 100644 index 0000000..984d05a --- /dev/null +++ b/packages/fixture-package-separate-indexes/.cuprc.js @@ -0,0 +1,5 @@ +module.exports = { + babel: { + presets: [require.resolve('babel-preset-react')], + }, +}; diff --git a/packages/fixture-package-separate-indexes/.eslintignore b/packages/fixture-package-separate-indexes/.eslintignore new file mode 100644 index 0000000..70aa607 --- /dev/null +++ b/packages/fixture-package-separate-indexes/.eslintignore @@ -0,0 +1,2 @@ +dist/ +flow-typed/ diff --git a/packages/fixture-package-separate-indexes/.eslintrc.js b/packages/fixture-package-separate-indexes/.eslintrc.js new file mode 100644 index 0000000..15e9cdb --- /dev/null +++ b/packages/fixture-package-separate-indexes/.eslintrc.js @@ -0,0 +1,37 @@ +module.exports = { + extends: [ + 'plugin:react/recommended', + require.resolve('eslint-config-cup'), + require.resolve('eslint-config-cup-recommended'), + ], + + parser: 'babel-eslint', + + parserOptions: { + ecmaVersion: 2018, + + ecmaFeatures: { + experimentalObjectRestSpread: true, + jsx: true, + }, + }, + + plugins: ['eslint-plugin-prettier'], + + rules: { + 'prettier/prettier': [ + 'error', + { + useTabs: false, + printWidth: 80, + tabWidth: 2, + singleQuote: true, + trailingComma: 'all', + bracketSpacing: false, + jsxBracketSameLine: false, + parser: 'babylon', + semi: true, + }, + ], + }, +}; diff --git a/packages/fixture-package-separate-indexes/.flowconfig b/packages/fixture-package-separate-indexes/.flowconfig new file mode 100644 index 0000000..43d2d77 --- /dev/null +++ b/packages/fixture-package-separate-indexes/.flowconfig @@ -0,0 +1,11 @@ +[ignore] +/dist/** +[include] + +[libs] + +[lints] + +[options] + +[strict] diff --git a/packages/fixture-package-separate-indexes/.gitignore b/packages/fixture-package-separate-indexes/.gitignore new file mode 100644 index 0000000..b9cb2d6 --- /dev/null +++ b/packages/fixture-package-separate-indexes/.gitignore @@ -0,0 +1,3 @@ +dist/ +dist-tests/ +coverage/ diff --git a/packages/fixture-package-separate-indexes/README.md b/packages/fixture-package-separate-indexes/README.md new file mode 100644 index 0000000..6c39f62 --- /dev/null +++ b/packages/fixture-package-separate-indexes/README.md @@ -0,0 +1,3 @@ +# fixture-package + +An example package using create-universal-package diff --git a/packages/fixture-package-separate-indexes/flow-typed/cup.js b/packages/fixture-package-separate-indexes/flow-typed/cup.js new file mode 100644 index 0000000..e7b9c53 --- /dev/null +++ b/packages/fixture-package-separate-indexes/flow-typed/cup.js @@ -0,0 +1,9 @@ +// @flow + +declare var __BROWSER__: boolean; +declare var __NODE__: boolean; +declare var __DEV__: boolean; + +declare module '@cup/fixture-dependency-pure' { + declare export default any +} diff --git a/packages/fixture-package-separate-indexes/package.json b/packages/fixture-package-separate-indexes/package.json new file mode 100644 index 0000000..735b76f --- /dev/null +++ b/packages/fixture-package-separate-indexes/package.json @@ -0,0 +1,63 @@ +{ + "name": "@cup/fixture-package-separate-indexes", + "private": true, + "version": "1.1.13", + "description": "A fixture universal package", + "author": "Ryan Tsao ", + "homepage": "https://github.com/rtsao/create-universal-package", + "repository": "git@github.com:rtsao/create-universal-package.git", + "bugs": "https://github.com/rtsao/create-universal-package/issues", + "files": [ + "dist", + "src" + ], + "main": "./dist/index.js", + "module": "./dist/index.es.js", + "browser": { + "./dist/index.js": "./dist/browser.es5.js", + "./dist/index.es.js": "./dist/browser.es5.es.js" + }, + "es2015": { + "./dist/browser.es5.es.js": "./dist/browser.es2015.es.js" + }, + "es2017": { + "./dist/browser.es5.es.js": "./dist/browser.es2017.es.js", + "./dist/browser.es2015.es.js": "./dist/browser.es2017.es.js" + }, + "scripts": { + "clean": "cup clean", + "pretest": "cup build-tests", + "test": "nyc --reporter=lcov unitest --browser=dist-tests/browser.js --node=dist-tests/node.js", + "build": "cup build --separate-entries", + "lint": "eslint src/**", + "prepublish": "npm run build" + }, + "dependencies": { + "@cup/fixture-dependency-pure": "^0.0.3", + "babel-eslint": "7" + }, + "peerDependencies": { + "react": "^16.1.0" + }, + "devDependencies": { + "babel-preset-cup": "^1.0.0-rc.3", + "babel-preset-react": "^7.0.0-beta.3", + "create-universal-package": "^3.2.6", + "enzyme": "^3.1.1", + "enzyme-adapter-react-16": "^1.0.4", + "eslint": "4.x", + "eslint-config-cup": "^1.0.0", + "eslint-config-cup-recommended": "^1.0.0", + "eslint-plugin-cup": "^1.0.0", + "eslint-plugin-prettier": "^2.0.1", + "eslint-plugin-react": "^7.5.1", + "nyc": "^11.3.0", + "prettier": "^1.2.2", + "react": "^16.1.0", + "react-dom": "^16.1.0", + "react-test-renderer": "^16.1.0", + "tape-cup": "^4.7.1", + "unitest": "^2.0.0" + }, + "license": "MIT" +} diff --git a/packages/fixture-package-separate-indexes/src/__tests__/helpers/index.js b/packages/fixture-package-separate-indexes/src/__tests__/helpers/index.js new file mode 100644 index 0000000..de000d3 --- /dev/null +++ b/packages/fixture-package-separate-indexes/src/__tests__/helpers/index.js @@ -0,0 +1,6 @@ +import test from 'tape-cup'; + +test('should not be run', t => { + t.fail('a failing assertion'); + t.end(); +}); diff --git a/packages/fixture-package-separate-indexes/src/__tests__/test.browser.js b/packages/fixture-package-separate-indexes/src/__tests__/test.browser.js new file mode 100644 index 0000000..a202e63 --- /dev/null +++ b/packages/fixture-package-separate-indexes/src/__tests__/test.browser.js @@ -0,0 +1,20 @@ +import test from 'tape-cup'; + +import {configure, mount} from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; +configure({adapter: new Adapter()}); + +import React from 'react'; + +import {Component} from '../index.browser.js'; + +test('a browser only test', t => { + t.pass('browser only assertion'); + t.end(); +}); + +test('full dom render', t => { + const wrapper = mount(); + t.ok(wrapper); + t.end(); +}); diff --git a/packages/fixture-package-separate-indexes/src/__tests__/test.node.js b/packages/fixture-package-separate-indexes/src/__tests__/test.node.js new file mode 100644 index 0000000..062a070 --- /dev/null +++ b/packages/fixture-package-separate-indexes/src/__tests__/test.node.js @@ -0,0 +1,20 @@ +import test from 'tape-cup'; + +import {configure, shallow} from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; +configure({adapter: new Adapter()}); + +import React from 'react'; + +import {Component} from '../index.node.js'; + +test('a node only test', t => { + t.pass('node only assertion'); + t.end(); +}); + +test('shallow render', t => { + const wrapper = shallow(); + t.ok(wrapper); + t.end(); +}); diff --git a/packages/fixture-package-separate-indexes/src/foo/__tests__/a-test.js b/packages/fixture-package-separate-indexes/src/foo/__tests__/a-test.js new file mode 100644 index 0000000..e854c5b --- /dev/null +++ b/packages/fixture-package-separate-indexes/src/foo/__tests__/a-test.js @@ -0,0 +1,22 @@ +import test from 'tape-cup'; + +import * as a from '../a.js'; + +test('a', t => { + t.equal(a.default, 'a'); + t.end(); +}); + +if (__NODE__) { + test('a (node)', t => { + t.equal(a.default, 'a'); + t.end(); + }); +} + +if (__BROWSER__) { + test('a (browser)', t => { + t.equal(a.default, 'a'); + t.end(); + }); +} diff --git a/packages/fixture-package-separate-indexes/src/foo/__tests__/b-test.js b/packages/fixture-package-separate-indexes/src/foo/__tests__/b-test.js new file mode 100644 index 0000000..fda7f03 --- /dev/null +++ b/packages/fixture-package-separate-indexes/src/foo/__tests__/b-test.js @@ -0,0 +1,8 @@ +import test from 'tape-cup'; + +import * as b from '../b.js'; + +test('b', t => { + t.equal(b.default, 'b'); + t.end(); +}); diff --git a/packages/fixture-package-separate-indexes/src/foo/a.js b/packages/fixture-package-separate-indexes/src/foo/a.js new file mode 100644 index 0000000..88f8e38 --- /dev/null +++ b/packages/fixture-package-separate-indexes/src/foo/a.js @@ -0,0 +1,3 @@ +const a = 'a'; + +export default a; diff --git a/packages/fixture-package-separate-indexes/src/foo/b.js b/packages/fixture-package-separate-indexes/src/foo/b.js new file mode 100644 index 0000000..0589f2f --- /dev/null +++ b/packages/fixture-package-separate-indexes/src/foo/b.js @@ -0,0 +1,3 @@ +const b = 'b'; + +export default b; diff --git a/packages/fixture-package-separate-indexes/src/index.browser.js b/packages/fixture-package-separate-indexes/src/index.browser.js new file mode 100644 index 0000000..1aa7398 --- /dev/null +++ b/packages/fixture-package-separate-indexes/src/index.browser.js @@ -0,0 +1,38 @@ +// @flow + +import a from './foo/a.js'; +import b from './foo/b.js'; +import pure from '@cup/fixture-dependency-pure'; +import React from 'react'; + +import crypto from 'crypto'; + +export function square(x: number) { + return x * x; +} + +export function hash(str: string) { + if (__BROWSER__) { + return str; + } else { + // crypto dependency should be eliminated from browser bundle + return crypto.createHmac('sha256', str).digest('hex'); + } +} + +if (__NODE__) { + // pure dependency should be eliminated from browser bundle + process.stdout.write(pure()); +} + +export function Component() { + return
Hello World
; +} + +export function Component2() { + return React.createElement('div'); +} + +export function log() { + return __DEV__ ? a : b; +} diff --git a/packages/fixture-package-separate-indexes/src/index.node.js b/packages/fixture-package-separate-indexes/src/index.node.js new file mode 100644 index 0000000..1aa7398 --- /dev/null +++ b/packages/fixture-package-separate-indexes/src/index.node.js @@ -0,0 +1,38 @@ +// @flow + +import a from './foo/a.js'; +import b from './foo/b.js'; +import pure from '@cup/fixture-dependency-pure'; +import React from 'react'; + +import crypto from 'crypto'; + +export function square(x: number) { + return x * x; +} + +export function hash(str: string) { + if (__BROWSER__) { + return str; + } else { + // crypto dependency should be eliminated from browser bundle + return crypto.createHmac('sha256', str).digest('hex'); + } +} + +if (__NODE__) { + // pure dependency should be eliminated from browser bundle + process.stdout.write(pure()); +} + +export function Component() { + return
Hello World
; +} + +export function Component2() { + return React.createElement('div'); +} + +export function log() { + return __DEV__ ? a : b; +}