Pārlūkot izejas kodu

Merge pull request #92 from transloadit/new-build

New build, npm-run-all and yo-yo rendering experiments
Artur Paikin 9 gadi atpakaļ
vecāks
revīzija
5eb35b8c34

+ 3 - 3
CHANGELOG.md

@@ -58,12 +58,12 @@ Theme: The aim low release
 
 
 Released: June 03, 2016
 Released: June 03, 2016
 
 
-- [ ] build: minification of the bundle (@arturi)
+- [x] build: minification of the bundle (@arturi)
 - [ ] build: supply pre-built bundle in npm (@arturi)
 - [ ] build: supply pre-built bundle in npm (@arturi)
-- [ ] build: switch to https://www.npmjs.com/package/npm-run-all instead of parallelshell (@kvz)
+- [x] build: switch to https://www.npmjs.com/package/npm-run-all instead of parallelshell (@kvz)
 - [ ] drive: Make sure uppy-server does not explode on special file types: https://dl.dropboxusercontent.com/s/d4dbxitjt8clo50/2016-05-06%20at%2022.41.png (@hedgerh)
 - [ ] drive: Make sure uppy-server does not explode on special file types: https://dl.dropboxusercontent.com/s/d4dbxitjt8clo50/2016-05-06%20at%2022.41.png (@hedgerh)
 - [ ] modal: accessibility. focus on the first input field / button in tab panel (@arturi)
 - [ ] modal: accessibility. focus on the first input field / button in tab panel (@arturi)
-- [ ] progressdrawer: figure out crazy rerendering of previews by yoyo (@arturi)
+- [ ] progressdrawer: figure out crazy rerendering of previews by yoyo/bel: https://github.com/shama/bel/issues/26 (@arturi)
 - [ ] progressdrawer: improve styles, add preview icons for all (@arturi)
 - [ ] progressdrawer: improve styles, add preview icons for all (@arturi)
 - [ ] server: Start implementing the `SERVER-PLAN.md` so that Google Drive files are actually uploaded to the endpoint (@hedgerh)
 - [ ] server: Start implementing the `SERVER-PLAN.md` so that Google Drive files are actually uploaded to the endpoint (@hedgerh)
 - [ ] test: Get IE4 on windows 3.11 to run Uppy and see it fall back to regular form upload (`api2.transloadit.com`) (@arturi)
 - [ ] test: Get IE4 on windows 3.11 to run Uppy and see it fall back to regular form upload (`api2.transloadit.com`) (@arturi)

+ 26 - 0
bin/build-css.js

@@ -0,0 +1,26 @@
+var sass = require('node-sass')
+var postcss = require('postcss')
+var autoprefixer = require('autoprefixer')
+var cssnano = require('cssnano')
+var chalk = require('chalk')
+var fs = require('fs')
+var mkdirp = require('mkdirp')
+
+mkdirp.sync('./dist/')
+
+function handleErr (err) {
+  console.error(chalk.red('✗ Error:'), chalk.red(err.message))
+}
+
+sass.render({file: './src/scss/uppy.scss'}, function (err, sassResult) {
+  if (err) handleErr(err)
+  postcss([ cssnano, autoprefixer ])
+    .process(sassResult.css)
+    .then(function (postCSSResult) {
+      postCSSResult.warnings().forEach(function (warn) {
+        console.warn(warn.toString())
+      })
+      fs.writeFileSync('./dist/uppy.min.css', postCSSResult.css)
+      console.info(chalk.green('✓ Built Uppy CSS:'), chalk.magenta('uppy.min.css'))
+    })
+})

+ 59 - 0
bin/build-js.js

@@ -0,0 +1,59 @@
+var path = require('path')
+var fs = require('fs')
+var babelify = require('babelify')
+var chalk = require('chalk')
+var mkdirp = require('mkdirp')
+var glob = require('glob')
+var browserify = require('browserify')
+// var rollupify = require('rollupify')
+
+mkdirp.sync('./dist/')
+
+function handleErr (err) {
+  console.error(chalk.red('✗ Error:'), chalk.red(err.message))
+}
+
+function buildUppyBundle () {
+  browserify('./src/index.js', { debug: true, standalone: 'Uppy' })
+    .plugin('minifyify', {
+      map: 'uppy.js.map',
+      output: './dist/uppy.js.map'
+    })
+    // .transform(rollupify)
+    .transform(babelify)
+    .on('error', handleErr)
+    .bundle()
+    // .pipe(exorcist('./dist/uppy.js.map'))
+    .pipe(fs.createWriteStream('./dist/uppy.min.js', 'utf8'))
+    .on('error', handleErr)
+    .on('finish', function () {
+      console.info(chalk.green('✓ Built Uppy bundle:'), chalk.magenta('uppy.min.js'))
+    })
+}
+
+function buildUppyLocales () {
+  mkdirp.sync('./dist/locales')
+  glob('./src/locales/*.js', function (err, files) {
+    if (err) console.log(err)
+    files.forEach(function (file) {
+      var fileName = path.basename(file, '.js')
+      browserify(file, { debug: true })
+        .plugin('minifyify', {
+          map: fileName + '.min.js.map',
+          output: './dist/locales/' + fileName + '.min.js.map'
+        })
+        // .transform(rollupify)
+        .transform(babelify)
+        .on('error', handleErr)
+        .bundle()
+        .pipe(fs.createWriteStream('./dist/locales/' + fileName + '.min.js', 'utf8'))
+        .on('error', handleErr)
+        .on('finish', function () {
+          console.info(chalk.green('✓ Built Uppy locale:'), chalk.magenta(fileName + '.min.js'))
+        })
+    })
+  })
+}
+
+buildUppyBundle()
+buildUppyLocales()

+ 24 - 0
example/index.html

@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>uppy</title>
+  </head>
+  <body>
+    <h1>Uppy is here</h1>
+    <button id="uppyModalOpener">Open Modal</button>
+    <link href="../dist/uppy.min.css" rel="stylesheet">
+    <script src="../dist/uppy.min.js"></script>
+    <script src="../dist/locales/ru_RU.min.js"></script>
+    <script>
+      var uppy = new Uppy.Core({locales: Uppy.locales.ru_RU, debug: true})
+        .use(Uppy.plugins.Modal, {trigger: '#uppyModalOpener'})
+        .use(Uppy.plugins.Dummy, {target: Uppy.plugins.Modal})
+        .run();
+    </script>
+
+    <script>
+      document.querySelector('#uppyModalOpener').click()
+    </script>
+  </body>
+</html>

+ 23 - 15
package.json

@@ -4,13 +4,13 @@
   "description": "Almost as cute as a Puppy :dog:",
   "description": "Almost as cute as a Puppy :dog:",
   "main": "src/index.js",
   "main": "src/index.js",
   "scripts": {
   "scripts": {
+    "build:bundle": "node ./bin/build-js.js",
+    "build:css": "node ./bin/build-css.js",
+    "size": "echo 'JS Size:' && cat ./dist/uppy.min.js | gzip | wc -c && echo 'CSS Size:' && cat ./dist/uppy.min.css | gzip | wc -c",
     "build:bundle:fullpath": "env OUT=uppy-fp.js ./bin/build-bundle --full-paths",
     "build:bundle:fullpath": "env OUT=uppy-fp.js ./bin/build-bundle --full-paths",
-    "build:bundle:min": "./bin/build-bundle",
-    "build:bundle": "./bin/build-bundle && ./bin/build-bundle-locales",
-    "build:css": "bin/build-css",
-    "build:js": "npm run build:lib && npm run build:bundle && npm run build:bundle:min",
+    "build:js": "npm-run-all --parallel build:bundle build:lib",
     "build:lib": "babel --version && babel src -d lib",
     "build:lib": "babel --version && babel src -d lib",
-    "build": "npm run build:lib && npm run build:bundle && npm run build:bundle:min && npm run build:css",
+    "build": "npm-run-all --parallel build:js build:css",
     "clean": "rm -rf lib && rm -rf dist",
     "clean": "rm -rf lib && rm -rf dist",
     "docs": "cd website && node node_modules/documentation/bin/documentation.js readme ../src/index.js --readme-file=src/api/docs.md --section 'Uppy Core & Plugins' -q --github -c doc-order.json",
     "docs": "cd website && node node_modules/documentation/bin/documentation.js readme ../src/index.js --readme-file=src/api/docs.md --section 'Uppy Core & Plugins' -q --github -c doc-order.json",
     "install": "npm run web:install",
     "install": "npm run web:install",
@@ -28,9 +28,9 @@
     "test": "npm run lint && npm run test:unit",
     "test": "npm run lint && npm run test:unit",
     "travis:deletecache": "travis cache --delete",
     "travis:deletecache": "travis cache --delete",
     "watch:css": "nodemon --watch src --ext scss -x 'npm run build:css && node website/update.js'",
     "watch:css": "nodemon --watch src --ext scss -x 'npm run build:css && node website/update.js'",
-    "watch:fast": "parallelshell 'npm run watch:css' 'npm run web:preview'",
+    "watch:fast": "npm-run-all --parallel watch:css web:preview",
     "watch:js": "nodemon --watch src --ext js -x 'npm run build:bundle && node website/update.js'",
     "watch:js": "nodemon --watch src --ext js -x 'npm run build:bundle && node website/update.js'",
-    "watch": "parallelshell 'npm run watch:js' 'npm run watch:css' && node website/update.js",
+    "watch": "npm-run-all --parallel watch:js watch:css && node website/update.js",
     "web:build": "cd website && node update.js && ./node_modules/.bin/hexo generate --silent && node build-examples.js",
     "web:build": "cd website && node update.js && ./node_modules/.bin/hexo generate --silent && node build-examples.js",
     "web:clean": "cd website && ./node_modules/.bin/hexo clean",
     "web:clean": "cd website && ./node_modules/.bin/hexo clean",
     "web:deploy": "npm run web:install && npm run web:disc && npm run docs && npm run web:build && ./bin/web-deploy",
     "web:deploy": "npm run web:install && npm run web:disc && npm run docs && npm run web:build && ./bin/web-deploy",
@@ -38,7 +38,8 @@
     "web:install": "cd website && npm install",
     "web:install": "cd website && npm install",
     "web:preview": "cd website && parallelshell 'node build-examples.js watch' './node_modules/.bin/hexo server'",
     "web:preview": "cd website && parallelshell 'node build-examples.js watch' './node_modules/.bin/hexo server'",
     "web:update:frontpage:code:sample": "cd website && ./node_modules/.bin/hexo generate && cp -f public/frontpage-code-sample.html ./themes/uppy/layout/partials/frontpage-code-sample.html",
     "web:update:frontpage:code:sample": "cd website && ./node_modules/.bin/hexo generate && cp -f public/frontpage-code-sample.html ./themes/uppy/layout/partials/frontpage-code-sample.html",
-    "web": "npm run web:clean && npm run web:build"
+    "web": "npm run web:clean && npm run web:build",
+    "prepublish": ""
   },
   },
   "repository": {
   "repository": {
     "type": "git",
     "type": "git",
@@ -51,21 +52,23 @@
   },
   },
   "homepage": "https://github.com/transloadit/uppy#readme",
   "homepage": "https://github.com/transloadit/uppy#readme",
   "devDependencies": {
   "devDependencies": {
-    "babel-cli": "6.6.5",
-    "babel-core": "6.7.4",
+    "autoprefixer": "6.3.6",
+    "babel-cli": "6.9.0",
+    "babel-core": "6.7.7",
     "babel-eslint": "6.0.2",
     "babel-eslint": "6.0.2",
     "babel-loader": "6.2.4",
     "babel-loader": "6.2.4",
     "babel-plugin-es6-promise": "1.0.0",
     "babel-plugin-es6-promise": "1.0.0",
     "babel-plugin-transform-object-assign": "6.5.0",
     "babel-plugin-transform-object-assign": "6.5.0",
     "babel-plugin-transform-proto-to-assign": "6.8.0",
     "babel-plugin-transform-proto-to-assign": "6.8.0",
     "babel-polyfill": "6.7.4",
     "babel-polyfill": "6.7.4",
-    "babel-preset-es2015": "6.6.0",
+    "babel-preset-es2015": "6.9.0",
     "babel-preset-es2015-loose": "7.0.0",
     "babel-preset-es2015-loose": "7.0.0",
     "babel-register": "6.7.2",
     "babel-register": "6.7.2",
     "babelify": "7.2.0",
     "babelify": "7.2.0",
     "browser-sync": "2.10.0",
     "browser-sync": "2.10.0",
     "browserify": "12.0.1",
     "browserify": "12.0.1",
     "chalk": "1.1.1",
     "chalk": "1.1.1",
+    "cssnano": "3.6.2",
     "disc": "1.3.2",
     "disc": "1.3.2",
     "es6-promise": "3.1.2",
     "es6-promise": "3.1.2",
     "eslint": "2.7.0",
     "eslint": "2.7.0",
@@ -73,16 +76,21 @@
     "eslint-plugin-promise": "1.1.0",
     "eslint-plugin-promise": "1.1.0",
     "eslint-plugin-standard": "1.3.2",
     "eslint-plugin-standard": "1.3.2",
     "fakefile": "0.0.5",
     "fakefile": "0.0.5",
+    "glob": "7.0.3",
     "isomorphic-fetch": "2.2.1",
     "isomorphic-fetch": "2.2.1",
+    "minifyify": "7.3.3",
+    "mkdirp": "0.5.1",
     "multi-glob": "1.0.1",
     "multi-glob": "1.0.1",
-    "nock": "^8.0.0",
-    "node-fetch": "^1.5.0",
+    "nock": "8.0.0",
+    "node-fetch": "1.5.0",
     "node-notifier": "4.4.0",
     "node-notifier": "4.4.0",
     "node-sass": "3.4.2",
     "node-sass": "3.4.2",
     "nodemon": "1.8.1",
     "nodemon": "1.8.1",
+    "npm-run-all": "2.1.1",
     "parallelshell": "2.0.0",
     "parallelshell": "2.0.0",
+    "postcss": "5.0.21",
     "selenium-webdriver": "2.52.0",
     "selenium-webdriver": "2.52.0",
-    "tap-spec": "^4.1.1",
+    "tap-spec": "4.1.1",
     "tape": "4.4.0",
     "tape": "4.4.0",
     "uppy-server": "0.0.7",
     "uppy-server": "0.0.7",
     "watchify": "3.6.1"
     "watchify": "3.6.1"
@@ -91,6 +99,6 @@
     "drag-drop": "2.11.0",
     "drag-drop": "2.11.0",
     "tus-js-client": "1.1.3",
     "tus-js-client": "1.1.3",
     "whatwg-fetch": "1.0.0",
     "whatwg-fetch": "1.0.0",
-    "yo-yo": "1.1.1"
+    "yo-yo": "1.2.0"
   }
   }
 }
 }

+ 3 - 3
src/core/Core.js

@@ -244,7 +244,7 @@ export default class Core {
   use (Plugin, opts) {
   use (Plugin, opts) {
     // Instantiate
     // Instantiate
     const plugin = new Plugin(this, opts)
     const plugin = new Plugin(this, opts)
-    const pluginName = Utils.getFnName(plugin.constructor)
+    const pluginName = plugin.id
     this.plugins[plugin.type] = this.plugins[plugin.type] || []
     this.plugins[plugin.type] = this.plugins[plugin.type] || []
 
 
     if (!pluginName) {
     if (!pluginName) {
@@ -258,7 +258,7 @@ export default class Core {
     let existsPluginAlready = this.getPlugin(pluginName)
     let existsPluginAlready = this.getPlugin(pluginName)
     if (existsPluginAlready) {
     if (existsPluginAlready) {
       let msg = `Already found a plugin named '${existsPluginAlready.name}'.
       let msg = `Already found a plugin named '${existsPluginAlready.name}'.
-        Tried to use: '${plugin.constructor.name}'.
+        Tried to use: '${pluginName}'.
         Uppy is currently limited to running one of every plugin.
         Uppy is currently limited to running one of every plugin.
         Share your use case with us over at
         Share your use case with us over at
         https://github.com/transloadit/uppy/issues/
         https://github.com/transloadit/uppy/issues/
@@ -279,7 +279,7 @@ export default class Core {
   getPlugin (name) {
   getPlugin (name) {
     let foundPlugin = false
     let foundPlugin = false
     this.iteratePlugins((plugin) => {
     this.iteratePlugins((plugin) => {
-      const pluginName = Utils.getFnName(plugin.constructor)
+      const pluginName = plugin.id
       if (pluginName === name) {
       if (pluginName === name) {
         foundPlugin = plugin
         foundPlugin = plugin
         return false
         return false

+ 9 - 5
src/plugins/Dummy.js

@@ -17,13 +17,17 @@ export default class Dummy extends Plugin {
 
 
     // merge default options with the ones set by user
     // merge default options with the ones set by user
     this.opts = Object.assign({}, defaultOptions, opts)
     this.opts = Object.assign({}, defaultOptions, opts)
+
+    this.strange = yo`<h1>this is strange 1</h1>`
   }
   }
 
 
-  render (state) {
+  render () {
+    const bla = yo`<h1>this is strange 2</h1>`
     return yo`
     return yo`
       <div class="wow-this-works">
       <div class="wow-this-works">
         <input type="text" value="hello">
         <input type="text" value="hello">
-        I am a dummy plugin, look at me, I was rendered in a modal! That’s crazy, I know.
+        ${this.strange}
+        ${bla}
       </div>
       </div>
     `
     `
   }
   }
@@ -33,8 +37,8 @@ export default class Dummy extends Plugin {
     firstInput.focus()
     firstInput.focus()
   }
   }
 
 
-  install (state) {
-    this.el = this.render(this.core.state)
-    this.target = this.getTarget(this.opts.target, this, this.el, this.render.bind(this))
+  install () {
+    this.el = this.render()
+    this.target = this.getTarget(this.opts.target, this, this.el, this.render)
   }
   }
 }
 }

+ 74 - 0
src/plugins/IndependentDummy.js

@@ -0,0 +1,74 @@
+import Utils from '../core/Utils'
+import yo from 'yo-yo'
+
+/**
+ * Independent Dummy
+ *
+ */
+export default class Dummy {
+  constructor (core, opts) {
+    // super(core, opts)
+    this.type = 'acquirer'
+    this.id = 'Dummy'
+    this.title = 'Dummy'
+    this.core = core
+
+    // set default options
+    const defaultOptions = {}
+
+    this.strange = yo`<h1>this is strange 1</h1>`
+
+    // merge default options with the ones set by user
+    this.opts = Object.assign({}, defaultOptions, opts)
+  }
+
+  getTarget (target, caller, el, render) {
+    const callerPluginName = Utils.getFnName(caller.constructor)
+
+    if (typeof target === 'string') {
+      this.core.log(`Installing ${callerPluginName} to ${target}`)
+
+      // clear everything inside the target selector
+      // if (replaceTargetContent) {
+      //   document.querySelector(target).innerHTML = ''
+      // }
+      document.querySelector(target).appendChild(el)
+
+      return target
+    } else {
+      const targetPluginName = Utils.getFnName(target)
+      this.core.log(`Installing ${callerPluginName} to ${targetPluginName}`)
+      let targetPlugin = this.core.getPlugin(targetPluginName)
+      let selectorTarget = targetPlugin.addTarget(caller, render)
+
+      return selectorTarget
+    }
+  }
+
+  update () {
+
+  }
+
+  render () {
+    const bla = yo`<h2>this is strange 2</h2>`
+    return yo`
+      <div class="wow-this-works">
+        <input type="text" value="hello">
+        I am a dummy plugin, look at me, I was rendered in a modal! That’s crazy, I know.
+        ${this.strange}
+        ${bla}
+      </div>
+    `
+  }
+
+  focus () {
+    const firstInput = document.querySelector(`${this.target} *:input[type!=hidden]:first`)
+    firstInput.focus()
+  }
+
+  install () {
+    this.el = this.render()
+    document.body.appendChild(this.el)
+    this.target = this.getTarget(this.opts.target, this, this.el, this.render.bind(this))
+  }
+}

+ 1 - 1
src/plugins/Modal.js

@@ -32,7 +32,7 @@ export default class Modal extends Plugin {
 
 
   addTarget (callerPlugin, render) {
   addTarget (callerPlugin, render) {
     const callerPluginId = callerPlugin.constructor.name
     const callerPluginId = callerPlugin.constructor.name
-    const callerPluginName = callerPlugin.name || callerPluginId
+    const callerPluginName = callerPlugin.title || callerPluginId
     const callerPluginIcon = callerPlugin.icon || this.opts.defaultTabIcon
     const callerPluginIcon = callerPlugin.icon || this.opts.defaultTabIcon
     const callerPluginType = callerPlugin.type
     const callerPluginType = callerPlugin.type
 
 

+ 4 - 3
src/plugins/Plugin.js

@@ -1,5 +1,4 @@
 import yo from 'yo-yo'
 import yo from 'yo-yo'
-import Utils from '../core/Utils'
 
 
 /**
 /**
  * Boilerplate that all Plugins share - and should not be used
  * Boilerplate that all Plugins share - and should not be used
@@ -37,7 +36,7 @@ export default class Plugin {
    *
    *
    */
    */
   getTarget (target, caller, el, render) {
   getTarget (target, caller, el, render) {
-    const callerPluginName = Utils.getFnName(caller.constructor)
+    const callerPluginName = caller.id
 
 
     if (typeof target === 'string') {
     if (typeof target === 'string') {
       this.core.log(`Installing ${callerPluginName} to ${target}`)
       this.core.log(`Installing ${callerPluginName} to ${target}`)
@@ -50,7 +49,9 @@ export default class Plugin {
 
 
       return target
       return target
     } else {
     } else {
-      const targetPluginName = Utils.getFnName(target)
+      // TODO: is this the way to roll just to get the plugin name?
+      const Target = target
+      const targetPluginName = new Target().id
       this.core.log(`Installing ${callerPluginName} to ${targetPluginName}`)
       this.core.log(`Installing ${callerPluginName} to ${targetPluginName}`)
       let targetPlugin = this.core.getPlugin(targetPluginName)
       let targetPlugin = this.core.getPlugin(targetPluginName)
       let selectorTarget = targetPlugin.addTarget(caller, render)
       let selectorTarget = targetPlugin.addTarget(caller, render)

+ 7 - 3
test/acceptance/dummy.spec.js

@@ -1,16 +1,20 @@
 var test = require('tape')
 var test = require('tape')
-var Driver = require('./Browser')
+var webdriver = require('selenium-webdriver')
+
+var driver = new webdriver
+  .Builder()
+  .forBrowser('firefox')
+  .build()
 
 
 test('open a page, create a variable and get its value', function (t) {
 test('open a page, create a variable and get its value', function (t) {
   t.plan(1)
   t.plan(1)
 
 
-  var driver = Driver.setDriver()
-
   driver.get('http://ya.ru')
   driver.get('http://ya.ru')
   driver.executeScript('window.a = "blabla";')
   driver.executeScript('window.a = "blabla";')
   driver.sleep(2000)
   driver.sleep(2000)
   driver.executeScript('return a').then(function (val) {
   driver.executeScript('return a').then(function (val) {
     console.log(val)
     console.log(val)
+    t.equal(val, 'blabla')
   })
   })
   driver.sleep(5000)
   driver.sleep(5000)
   driver.quit()
   driver.quit()

+ 27 - 0
website/src/uppy.ejs

@@ -0,0 +1,27 @@
+---
+layout: false
+title: Uppy
+permalink: uppy/
+---
+
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>uppy</title>
+  </head>
+  <body>
+    <h1>Uppy is here</h1>
+    <button id="uppyModalOpener">Open Modal</button>
+    <link href="uppy.min.css" rel="stylesheet">
+    <script src="uppy.min.js"></script>
+    <script src="locales/ru_RU.min.js"></script>
+    <script>
+      var uppy = new Uppy.Core({locales: Uppy.locales.ru_RU, debug: true})
+      // uppy.use(Uppy.plugins.DragDrop, {target: 'body'});
+        .use(Uppy.plugins.Modal, {trigger: '#uppyModalOpener'})
+        .use(Uppy.plugins.Dummy, {target: Uppy.plugins.Modal})
+        .run();
+    </script>
+  </body>
+</html>