diff --git a/.gitignore b/.gitignore index cddf00b..d388f83 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ node_modules build dist package-lock.json +yarn.lock diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e9b7612 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Jason Miller + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index a796f0f..4e39bd7 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Microbundle includes two commands - `build` (the default) and `watch`. Neither r ### `microbundle` / `microbundle build` By default, microbundle will infer the location of your source entry file -(the root module in your program) from the `module` field in your `package.json`. It will infer the output directory and filename(s) from the `main` field. +(the root module in your program) from the `source` field in your `package.json`. It will infer the output directory and filename(s) from the `main` field. For UMD builds, microbundle will use a snake case version of the `name` field in your `package.json` for the export name; you can also specify a name via an `amdName` field or the `name` CLI option. ### `microbundle watch` @@ -72,6 +72,7 @@ Options: [boolean] [default: true] --strict Enforce undefined global context and add "use strict" [default: false] + --name Specify name exposed in UMD builds [string] ``` diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..162d68f --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,16 @@ +environment: + nodejs_version: "8" + +install: + - ps: Install-Product node $env:nodejs_version + - npm install + +test_script: + - node --version + - npm --version + - npm test + +build: off + +cache: + - node_modules diff --git a/package.json b/package.json index 43ecd9c..595e688 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "microbundle", - "version": "0.2.3", + "version": "0.2.4", "description": "Zero-configuration bundler for tiny JS libs, powered by Rollup.", "main": "dist/microbundle.js", "source": "src/index.js", @@ -32,10 +32,14 @@ "author": "Jason Miller (http://jasonformat.com)", "license": "MIT", "dependencies": { + "acorn-jsx": "4.1.0", "asyncro": "^2.0.1", + "autoprefixer": "^7.2.3", "babel-polyfill": "^6.26.0", + "camelcase": "^4.1.0", "chalk": "^2.3.0", "es6-promisify": "^5.0.0", + "glob": "^7.1.2", "gzip-size": "^4.1.0", "pretty-bytes": "^4.0.2", "regenerator-runtime": "^0.11.1", @@ -48,6 +52,7 @@ "rollup-plugin-node-resolve": "^3.0.0", "rollup-plugin-nodent": "^0.1.3", "rollup-plugin-post-replace": "^1.0.0", + "rollup-plugin-postcss": "^0.5.5", "rollup-plugin-preserve-shebang": "^0.1.3", "rollup-plugin-sizes": "^0.4.2", "rollup-plugin-typescript2": "^0.8.4", diff --git a/src/cli.js b/src/cli.js index fd633f3..3c329e1 100644 --- a/src/cli.js +++ b/src/cli.js @@ -36,6 +36,10 @@ yargs description: 'Enforce undefined global context and add "use strict"', default: false }) + .option('name', { + description: 'Specify name exposed in UMD builds', + default: false + }) .command( ['build [entries..]', '$0 [entries..]'], 'Build once and exit', diff --git a/src/index.js b/src/index.js index 0e7345a..45007b9 100644 --- a/src/index.js +++ b/src/index.js @@ -3,25 +3,29 @@ import { resolve, relative, dirname, basename, extname } from 'path'; import chalk from 'chalk'; import { map, series } from 'asyncro'; import promisify from 'es6-promisify'; +import glob from 'glob'; +import autoprefixer from 'autoprefixer'; import { rollup, watch } from 'rollup'; import nodent from 'rollup-plugin-nodent'; import commonjs from 'rollup-plugin-commonjs'; import nodeResolve from 'rollup-plugin-node-resolve'; import buble from 'rollup-plugin-buble'; import uglify from 'rollup-plugin-uglify'; -import replace from 'rollup-plugin-post-replace'; +import postcss from 'rollup-plugin-postcss'; +// import replace from 'rollup-plugin-post-replace'; import es3 from 'rollup-plugin-es3'; import gzipSize from 'gzip-size'; import prettyBytes from 'pretty-bytes'; import shebangPlugin from 'rollup-plugin-preserve-shebang'; import flow from 'rollup-plugin-flow'; import typescript from 'rollup-plugin-typescript2'; +import camelCase from 'camelcase'; const readFile = promisify(fs.readFile); const stat = promisify(fs.stat); const isDir = name => stat(name).then( stats => stats.isDirectory() ).catch( () => false ); const isFile = name => stat(name).then( stats => stats.isFile() ).catch( () => false ); -const safeVariableName = name => name.replace(/(?:^[^a-z$_]|([^a-z0-9_$]+))/g, '_'); +const safeVariableName = name => camelCase(name.toLowerCase().replace(/((^[^a-zA-Z]+)|[^\w.-])|([^a-zA-Z0-9]+$)/g, '')); const FORMATS = ['es', 'cjs', 'umd']; @@ -36,15 +40,21 @@ export default async function microbundle(options) { options.pkg = JSON.parse(await readFile(resolve(cwd, 'package.json'), 'utf8')); } catch (err) { - console.warn(`Unable to find package.json:\n ${err.message}`); - options.pkg = { - name: basename(options.cwd) - }; + console.warn(chalk.yellow(`${chalk.yellow.inverse('WARN')} no package.json found.`)); + let msg = String(err.message || err); + if (!msg.match(/ENOENT/)) console.warn(` ${chalk.red.dim(msg)}`); + options.pkg = {}; } - options.input = [].concat( + if (!options.pkg.name) { + options.pkg.name = basename(options.cwd); + console.warn(chalk.yellow(`${chalk.yellow.inverse('WARN')} missing package.json "name" field. Assuming "${options.pkg.name}".`)); + } + + options.input = []; + [].concat( options.entries && options.entries.length ? options.entries : options.pkg.source || (await isDir(resolve(cwd, 'src')) && 'src/index.js') || (await isFile(resolve(cwd, 'index.js')) && 'index.js') || options.pkg.module - ).map( file => resolve(cwd, file) ); + ).map( file => glob.sync(resolve(cwd, file)) ).forEach( file => options.input.push(...file) ); let main = resolve(cwd, options.output || options.pkg.main || 'dist'); if (!main.match(/\.[a-z]+$/) || await isDir(main)) { @@ -149,7 +159,7 @@ function createConfig(options, entry, format) { let mainNoExtension = options.output; if (options.multipleEntries) { - let name = entry.match(/\/index(\.(umd|cjs|es|m))?\.js$/) ? mainNoExtension : entry; + let name = entry.match(/(\\|\/)index(\.(umd|cjs|es|m))?\.js$/) ? mainNoExtension : entry; mainNoExtension = resolve(dirname(mainNoExtension), basename(name)); } mainNoExtension = mainNoExtension.replace(/(\.(umd|cjs|es|m))?\.js$/, ''); @@ -158,13 +168,19 @@ function createConfig(options, entry, format) { let cjsMain = replaceName(pkg['cjs:main'] || 'x.js', mainNoExtension); let umdMain = replaceName(pkg['umd:main'] || 'x.umd.js', mainNoExtension); - let rollupName = safeVariableName(basename(entry).replace(/\.js$/, '')); + // let rollupName = safeVariableName(basename(entry).replace(/\.js$/, '')); let config = { inputOptions: { input: entry, external, plugins: [ + postcss({ + plugins: [ + autoprefixer() + ], + extract: true + }), extname(entry)==='ts' && typescript({ tsconfigOverride: { compilerOptions: { @@ -179,35 +195,41 @@ function createConfig(options, entry, format) { promises: true, transformations: { forOf: false + }, + parser: { + plugins: { + jsx: require('acorn-jsx') + } } }), buble({ exclude: 'node_modules/**', jsx: options.jsx || 'h', objectAssign: options.assign || 'Object.assign', - transforms: { dangerousForOf: true } + transforms: { dangerousForOf: true, dangerousTaggedTemplateString: true } }), useNodeResolve && commonjs({ include: 'node_modules/**' }), useNodeResolve && nodeResolve({ - modulesOnly: true, + module: true, jsnext: true }), es3(), - format==='cjs' && replace({ - [`module.exports = ${rollupName};`]: '', - [`var ${rollupName} =`]: 'module.exports =' - }), + // 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' - }), + // format==='es' && replace({ + // [`export default ${rollupName};`]: '', + // [`var ${rollupName} =`]: 'export default' + // }), format!=='es' && options.compress!==false && uglify({ output: { comments: false }, mangle: { diff --git a/test/demo/package.json b/test/demo/package.json deleted file mode 100644 index e38ae2e..0000000 --- a/test/demo/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "name": "demo" -}