diff --git a/.gitignore b/.gitignore index fe2f58b..cb18a8d 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ yarn.lock .vscode .idea .rts2* +sizes.csv diff --git a/package.json b/package.json index 09f4a36..283ccc7 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,9 @@ "@babel/core": "^7.4.4", "@babel/plugin-proposal-class-properties": "7.4.4", "@babel/plugin-syntax-jsx": "^7.2.0", + "@babel/plugin-transform-react-jsx": "^7.3.0", "@babel/polyfill": "^7.4.4", + "@babel/preset-flow": "^7.0.0", "asyncro": "^3.0.0", "autoprefixer": "^9.5.1", "babel-plugin-transform-async-to-promises": "^0.8.10", @@ -61,10 +63,9 @@ "pretty-bytes": "^5.2.0", "rollup": "^1.11.3", "rollup-plugin-alias": "^1.5.1", - "rollup-plugin-babel": "^4.1.0-0", - "rollup-plugin-buble": "^0.19.4", - "rollup-plugin-bundle-size": "^1.0.3", - "rollup-plugin-commonjs": "^9.3.4", + "rollup-plugin-babel": "^4.3.2", + "rollup-plugin-bundle-size": "^1.0.1", + "rollup-plugin-commonjs": "^9.0.0", "rollup-plugin-es3": "^1.1.0", "rollup-plugin-flow": "^1.1.1", "rollup-plugin-json": "^4.0.0", @@ -80,6 +81,7 @@ "devDependencies": { "@babel/cli": "^7.4.4", "@babel/node": "^7.2.2", + "@babel/plugin-proposal-throw-expressions": "^7.2.0", "@babel/preset-env": "^7.4.4", "babel-core": "^7.0.0-bridge.0", "babel-jest": "^24.8.0", @@ -89,6 +91,7 @@ "eslint-config-developit": "^1.1.1", "eslint-config-prettier": "^4.2.0", "eslint-plugin-prettier": "^3.0.1", + "esm": "^3.2.22", "fs-extra": "^7.0.1", "husky": "^2.2.0", "jest": "^24.8.0", diff --git a/src/index.js b/src/index.js index 1822a22..657cb0b 100644 --- a/src/index.js +++ b/src/index.js @@ -9,7 +9,6 @@ import { rollup, watch } from 'rollup'; import commonjs from 'rollup-plugin-commonjs'; import babel from 'rollup-plugin-babel'; import nodeResolve from 'rollup-plugin-node-resolve'; -import buble from 'rollup-plugin-buble'; import { terser } from 'rollup-plugin-terser'; import alias from 'rollup-plugin-alias'; import postcss from 'rollup-plugin-postcss'; @@ -18,7 +17,6 @@ import brotliSize from 'brotli-size'; import prettyBytes from 'pretty-bytes'; import typescript from 'rollup-plugin-typescript2'; import json from 'rollup-plugin-json'; -import flow from './lib/flow-plugin'; import logError from './log-error'; import { readFile, isDir, isFile, stdout, stderr } from './utils'; import camelCase from 'camelcase'; @@ -529,7 +527,8 @@ function createConfig(options, entry, format, writeMeta) { compilerOptions: { sourceMap: options.sourcemap, declaration: true, - jsx: options.jsx, + jsx: 'react', + jsxFactory: options.jsx || 'h', }, }, tsconfigOverride: { @@ -538,7 +537,6 @@ function createConfig(options, entry, format, writeMeta) { }, }, }), - !useTypescript && flow({ all: true, pretty: true }), babel({ babelrc: false, configFile: false, @@ -551,18 +549,31 @@ function createConfig(options, entry, format, writeMeta) { ], ], }), - // Only used for async await babel({ - // We mainly use bublé to transpile JS and only use babel to - // transpile down `async/await`. To prevent conflicts with user - // supplied configurations we set this option to false. Note - // that we never supported using custom babel configs anyway. - babelrc: false, - configFile: false, extensions: EXTENSIONS, exclude: 'node_modules/**', + passPerPreset: true, // @see https://babeljs.io/docs/en/options#passperpreset + presets: [ + [ + '@babel/preset-env', + { + loose: true, + modules: false, + targets: + options.target === 'node' ? { node: '8' } : undefined, + exclude: ['transform-async-to-generator'], + }, + ], + !useTypescript && ['@babel/preset-flow', { all: true }], + ].filter(Boolean), plugins: [ - require.resolve('@babel/plugin-syntax-jsx'), + [ + require.resolve('@babel/plugin-transform-react-jsx'), + { + pragma: options.jsx || 'h', + pragmaFrag: options.jsxFragment || 'Fragment', + }, + ], [ require.resolve('babel-plugin-transform-replace-expressions'), { replace: defines }, @@ -577,29 +588,6 @@ function createConfig(options, entry, format, writeMeta) { ], ], }), - buble({ - exclude: 'node_modules/**', - jsx: options.jsx || 'h', - objectAssign: options.assign || 'Object.assign', - transforms: { - dangerousForOf: true, - dangerousTaggedTemplateString: true, - }, - }), - // We should upstream this to rollup - // format==='cjs' && replace({ - // [`module.exports = ${rollupName};`]: '', - // [`var ${rollupName} =`]: 'module.exports =' - // }), - // This works for the general case, but could cause nasty scope bugs. - // format==='umd' && replace({ - // [`return ${rollupName};`]: '', - // [`var ${rollupName} =`]: 'return' - // }), - // format==='es' && replace({ - // [`export default ${rollupName};`]: '', - // [`var ${rollupName} =`]: 'export default' - // }), options.compress !== false && [ terser({ sourcemap: true, diff --git a/src/lib/flow-plugin.js b/src/lib/flow-plugin.js deleted file mode 100644 index b90705d..0000000 --- a/src/lib/flow-plugin.js +++ /dev/null @@ -1,12 +0,0 @@ -import flow from 'rollup-plugin-flow'; - -export default function fixedFlow(options) { - let plugin = flow(options); - return Object.assign({}, plugin, { - transform(code, id) { - let ret = plugin.transform(code, id); - if (ret && ret.code === code) return null; - return ret; - }, - }); -} diff --git a/test/__snapshots__/index.test.js.snap b/test/__snapshots__/index.test.js.snap index a51990c..538a788 100644 --- a/test/__snapshots__/index.test.js.snap +++ b/test/__snapshots__/index.test.js.snap @@ -117,30 +117,30 @@ async-ts Build \\"asyncTs\\" to dist: -75 B: async-ts.js.gz -57 B: async-ts.js.br -77 B: async-ts.mjs.gz -63 B: async-ts.mjs.br -180 B: async-ts.umd.js.gz -139 B: async-ts.umd.js.br" +84 B: async-ts.js.gz +61 B: async-ts.js.br +94 B: async-ts.mjs.gz +76 B: async-ts.mjs.br +187 B: async-ts.umd.js.gz +150 B: async-ts.umd.js.br" `; exports[`fixtures build async-ts with microbundle 2`] = `7`; exports[`fixtures build async-ts with microbundle 3`] = ` -"var o=function(){};o.prototype.foo=function(){},exports.MyClass=o; +"exports.MyClass=function(){function o(){}return o.prototype.foo=function(){},o}(); //# sourceMappingURL=async-ts.js.map " `; exports[`fixtures build async-ts with microbundle 4`] = ` -"var o=function(){};o.prototype.foo=function(){};export{o as MyClass}; +"var o=function(){function o(){}return o.prototype.foo=function(){},o}();export{o as MyClass}; //# sourceMappingURL=async-ts.mjs.map " `; exports[`fixtures build async-ts with microbundle 5`] = ` -"!function(e,o){\\"object\\"==typeof exports&&\\"undefined\\"!=typeof module?o(exports):\\"function\\"==typeof define&&define.amd?define([\\"exports\\"],o):o((e=e||self).asyncTs={})}(this,function(e){var o=function(){};o.prototype.foo=function(){},e.MyClass=o}); +"!function(e,n){\\"object\\"==typeof exports&&\\"undefined\\"!=typeof module?n(exports):\\"function\\"==typeof define&&define.amd?define([\\"exports\\"],n):n((e=e||self).asyncTs={})}(this,function(e){e.MyClass=function(){function e(){}return e.prototype.foo=function(){},e}()}); //# sourceMappingURL=async-ts.umd.js.map " `; @@ -172,34 +172,81 @@ basic Build \\"basicLib\\" to dist: -202 B: basic-lib.js.gz -145 B: basic-lib.js.br -203 B: basic-lib.mjs.gz -145 B: basic-lib.mjs.br -287 B: basic-lib.umd.js.gz -222 B: basic-lib.umd.js.br" +229 B: basic-lib.js.gz +174 B: basic-lib.js.br +230 B: basic-lib.mjs.gz +177 B: basic-lib.mjs.br +313 B: basic-lib.umd.js.gz +251 B: basic-lib.umd.js.br" `; exports[`fixtures build basic with microbundle 2`] = `6`; exports[`fixtures build basic with microbundle 3`] = ` -"var r=function(){for(var r=[],e=arguments.length;e--;)r[e]=arguments[e];try{return Promise.resolve(r.reduce(function(r,e){return r+e},0))}catch(r){return Promise.reject(r)}};module.exports=function(){for(var e=[],t=arguments.length;t--;)e[t]=arguments[t];try{return Promise.resolve(r.apply(void 0,e)).then(function(t){return Promise.resolve(r.apply(void 0,e)).then(function(r){return[t,r]})})}catch(r){return Promise.reject(r)}}; +"var r=function(){try{for(var r=arguments.length,e=new Array(r),n=0;n0;)o[e]=arguments[e+2];return{tag:r,props:n,children:o}},n=function(){};n.prototype.render=function(){return r(\\"div\\",{id:\\"app\\"},r(\\"h1\\",null,\\"Hello, World!\\"),r(\\"p\\",null,\\"A JSX demo.\\"))},module.exports=n; +"var r=function(r,n){for(var e=arguments.length,o=new Array(e>2?e-2:0),t=2;t0;)e[o]=arguments[o+2];return{tag:r,props:n,children:e}},n=function(){};n.prototype.render=function(){return r(\\"div\\",{id:\\"app\\"},r(\\"h1\\",null,\\"Hello, World!\\"),r(\\"p\\",null,\\"A JSX demo.\\"))};export default n; +"var r=function(r,n){for(var e=arguments.length,t=new Array(e>2?e-2:0),o=2;o0;)o[t]=arguments[t+2];return{tag:e,props:n,children:o}},n=function(){};return n.prototype.render=function(){return e(\\"div\\",{id:\\"app\\"},e(\\"h1\\",null,\\"Hello, World!\\"),e(\\"p\\",null,\\"A JSX demo.\\"))},n}); +"!function(e,n){\\"object\\"==typeof exports&&\\"undefined\\"!=typeof module?module.exports=n():\\"function\\"==typeof define&&define.amd?define(n):(e=e||self).basicLibTsx=n()}(this,function(){var e=function(e,n){for(var o=arguments.length,t=new Array(o>2?o-2:0),r=2;r0;)o[e]=arguments[e+2];return{tag:r,props:n,children:o}},n=function(){};n.prototype.render=function(){return r(\\"div\\",{id:\\"app\\"},r(\\"h1\\",null,\\"Hello, World!\\"),r(\\"p\\",null,\\"A JSX demo.\\"))},module.exports=n; +"var n=function(n,r){for(var e=arguments.length,t=new Array(e>2?e-2:0),l=2;l0;)e[o]=arguments[o+2];return{tag:r,props:n,children:e}},n=function(){};n.prototype.render=function(){return r(\\"div\\",{id:\\"app\\"},r(\\"h1\\",null,\\"Hello, World!\\"),r(\\"p\\",null,\\"A JSX demo.\\"))};export default n; +"var n=function(n,r){for(var e=arguments.length,t=new Array(e>2?e-2:0),l=2;l0;)o[t]=arguments[t+2];return{tag:e,props:n,children:o}},n=function(){};return n.prototype.render=function(){return e(\\"div\\",{id:\\"app\\"},e(\\"h1\\",null,\\"Hello, World!\\"),e(\\"p\\",null,\\"A JSX demo.\\"))},n}); +"!function(n,e){\\"object\\"==typeof exports&&\\"undefined\\"!=typeof module?module.exports=e():\\"function\\"==typeof define&&define.amd?define(e):(n=n||self).jsx=e()}(this,function(){var n=function(n,e){for(var t=arguments.length,r=new Array(t>2?t-2:0),o=2;o ({ tag, props, children }); +// eslint-disable-next-line no-unused-vars +const Fragment = ({ children }) => children; export default class Foo { render() { @@ -6,6 +8,9 @@ export default class Foo {

Hello, World!

A JSX demo.

+ <> +

Test fragment

+
); } diff --git a/test/index.test.js b/test/index.test.js index 7596f03..e7ee269 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,15 +1,8 @@ import { resolve } from 'path'; import fs from 'fs-extra'; -import { promisify } from 'es6-promisify'; import dirTree from 'directory-tree'; -import shellQuote from 'shell-quote'; -import _rimraf from 'rimraf'; import { strip } from './lib/util'; -import { readFile } from '../src/utils'; -import createProg from '../src/prog'; -import microbundle from '../src/index'; - -const rimraf = promisify(_rimraf); +import { buildDirectory, getBuildScript } from '../tools/build-fixture'; const FIXTURES_DIR = `${__dirname}/fixtures`; const DEFAULT_SCRIPT = 'microbundle'; @@ -31,29 +24,6 @@ const printTree = (nodes, indentLevel = 0) => { ); }; -const getBuildScript = async (fixturePath, defaultScript) => { - let pkg = {}; - try { - pkg = JSON.parse( - await readFile(resolve(fixturePath, 'package.json'), 'utf8'), - ); - } catch (err) { - if (err.code !== 'ENOENT') throw err; - } - return (pkg && pkg.scripts && pkg.scripts.build) || defaultScript; -}; - -const parseScript = (() => { - let parsed; - const prog = createProg(_parsed => (parsed = _parsed)); - return script => { - const argv = shellQuote.parse(`node ${script}`); - // assuming {op: 'glob', pattern} for non-string args - prog(argv.map(arg => (typeof arg === 'string' ? arg : arg.pattern))); - return parsed; - }; -})(); - describe('fixtures', () => { const dirs = fs .readdirSync(FIXTURES_DIR) @@ -69,38 +39,20 @@ describe('fixtures', () => { fixturePath = resolve(fixturePath, fixtureDir.replace('-with-cwd', '')); } - const dist = resolve(`${fixturePath}/dist`); - // clean up - await rimraf(dist); - await rimraf(resolve(`${fixturePath}/.rts2_cache_cjs`)); - await rimraf(resolve(`${fixturePath}/.rts2_cache_es`)); - await rimraf(resolve(`${fixturePath}/.rts2_cache_umd`)); - - const script = await getBuildScript(fixturePath, DEFAULT_SCRIPT); - - const prevDir = process.cwd(); - process.chdir(resolve(fixturePath)); - - const parsedOpts = parseScript(script); - - const output = await microbundle({ - ...parsedOpts, - cwd: parsedOpts.cwd !== '.' ? parsedOpts.cwd : resolve(fixturePath), - }); - - process.chdir(prevDir); + const output = await buildDirectory(fixtureDir); const printedDir = printTree([dirTree(fixturePath)]); expect( [ - `Used script: ${script}`, + `Used script: ${await getBuildScript(fixturePath, DEFAULT_SCRIPT)}`, 'Directory tree:', printedDir, strip(output), ].join('\n\n'), ).toMatchSnapshot(); + const dist = resolve(`${fixturePath}/dist`); const files = fs.readdirSync(resolve(dist)); expect(files.length).toMatchSnapshot(); // we don't realy care about the content of a sourcemap diff --git a/tools/build-fixture.js b/tools/build-fixture.js new file mode 100644 index 0000000..60c522e --- /dev/null +++ b/tools/build-fixture.js @@ -0,0 +1,66 @@ +import { resolve } from 'path'; +import { promisify } from 'es6-promisify'; +import shellQuote from 'shell-quote'; +import _rimraf from 'rimraf'; +import { readFile } from '../src/utils'; +import createProg from '../src/prog'; +import microbundle from '../src/index'; + +const rimraf = promisify(_rimraf); + +const FIXTURES_DIR = resolve(`${__dirname}/../test/fixtures`); +const DEFAULT_SCRIPT = 'microbundle'; + +const parseScript = (() => { + let parsed; + const prog = createProg(_parsed => (parsed = _parsed)); + + return script => { + const argv = shellQuote.parse(`node ${script}`); + // assuming {op: 'glob', pattern} for non-string args + prog(argv.map(arg => (typeof arg === 'string' ? arg : arg.pattern))); + return parsed; + }; +})(); + +export const getBuildScript = async (fixturePath, defaultScript) => { + let pkg = {}; + try { + pkg = JSON.parse( + await readFile(resolve(fixturePath, 'package.json'), 'utf8'), + ); + } catch (err) { + if (err.code !== 'ENOENT') throw err; + } + return (pkg && pkg.scripts && pkg.scripts.build) || defaultScript; +}; + +export const buildDirectory = async fixtureDir => { + let fixturePath = resolve(FIXTURES_DIR, fixtureDir); + if (fixtureDir.endsWith('-with-cwd')) { + fixturePath = resolve(fixturePath, fixtureDir.replace('-with-cwd', '')); + } + + const dist = resolve(`${fixturePath}/dist`); + // clean up + await rimraf(dist); + await rimraf(resolve(`${fixturePath}/.rts2_cache_cjs`)); + await rimraf(resolve(`${fixturePath}/.rts2_cache_es`)); + await rimraf(resolve(`${fixturePath}/.rts2_cache_umd`)); + + const script = await getBuildScript(fixturePath, DEFAULT_SCRIPT); + + const prevDir = process.cwd(); + process.chdir(resolve(fixturePath)); + + const parsedOpts = parseScript(script); + let output = ''; + output = await microbundle({ + ...parsedOpts, + cwd: parsedOpts.cwd !== '.' ? parsedOpts.cwd : resolve(fixturePath), + }); + + process.chdir(prevDir); + + return output; +}; diff --git a/tools/generate-filesize.js b/tools/generate-filesize.js new file mode 100644 index 0000000..3fc4bc1 --- /dev/null +++ b/tools/generate-filesize.js @@ -0,0 +1,50 @@ +// eslint-ignore +require = require('esm')(module); + +const { resolve } = require('path'); +const fs = require('fs-extra'); +const { buildDirectory } = require('./build-fixture'); + +const FIXTURES_DIR = `${__dirname}/../test/fixtures`; + +const each = fn => arr => { + arr = Array.isArray(arr) ? arr : [arr]; + + return arr + .reduce( + (prev, curr, i) => prev.then(() => fn(curr, i, arr.length)), + Promise.resolve(), + ) + .then(() => arr); +}; + +const dirs = fs + .readdirSync(FIXTURES_DIR) + .filter(fixturePath => + fs.statSync(resolve(FIXTURES_DIR, fixturePath)).isDirectory(), + ); + +(async () => { + const csv = []; + + await each(async fixtureDir => { + let fixturePath = resolve(FIXTURES_DIR, fixtureDir); + if (fixtureDir.endsWith('-with-cwd')) { + fixturePath = resolve(fixturePath, fixtureDir.replace('-with-cwd', '')); + } + + await buildDirectory(fixtureDir); + + const dist = resolve(`${fixturePath}/dist`); + fs.readdirSync(dist) + .filter(file => !/\.map$/.test(file)) + .forEach(file => { + const size = fs.statSync(resolve(`${dist}/${file}`)).size; + csv.push(`${fixtureDir}/${file},${size}`); + }); + })(dirs); + + csv.unshift('file,size'); + + fs.writeFile(resolve(__dirname, '../sizes.csv'), csv.join('\n')); +})();