From 8bd6f3bf1631d89101ded3404d5f5643a4cf8807 Mon Sep 17 00:00:00 2001 From: Noam Elboim Date: Wed, 11 Oct 2017 15:09:36 +0300 Subject: [PATCH 01/12] creating a 'bin' script for CLI. --- bin/uizoo.js | 12 ++++ package.json | 12 ++-- server/generate/index.js | 83 ++++++++++++++++++++++++++ server/generate/templates/package.json | 4 ++ server/logo.js | 11 ++++ server/server.js | 3 - 6 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 bin/uizoo.js create mode 100644 server/generate/index.js create mode 100644 server/generate/templates/package.json create mode 100644 server/logo.js diff --git a/bin/uizoo.js b/bin/uizoo.js new file mode 100644 index 0000000..1b743e2 --- /dev/null +++ b/bin/uizoo.js @@ -0,0 +1,12 @@ +#!/usr/bin/env node + +const chalk = require('chalk'); +const logo = require('../server/logo'); +const log = console.log; + +log(` +Welcome to the ~ + ${chalk.bold(chalk.cyan(logo))} +`); + +require('../server/generate')(); \ No newline at end of file diff --git a/package.json b/package.json index 4dfa028..8123c15 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uizoo", - "version": "1.1.1", + "version": "1.2.0", "description": "Dynamic React Component Library", "scripts": { "start": "npm run gulp:w", @@ -25,16 +25,21 @@ "url": "https://github.com/myheritage/uizoo.js/issues" }, "homepage": "https://github.com/myheritage/uizoo.js#readme", + "bin": { + "uizoo": "./bin/uizoo.js" + }, "dependencies": { "babel-standalone": "~6.25.0", "body-parser": "~1.15.2", + "chalk": "~1.1.3", "compression": "~1.6.2", "cors": "~2.8.3", "doctrine-standalone": "~1.0.0", "express": "~4.15.2", + "fs-extra": "~4.0.2", "glob": "7.0.6", - "helmet": "~3.1.0", - "jsx-to-string": "~1.1.0", + "inquirer": "~3.3.0", + "latest-version": "^3.1.0", "react": "~16.0.0", "react-dom": "~16.0.0", "react-router-dom": "~4.2.2", @@ -45,7 +50,6 @@ }, "license": "MIT", "devDependencies": { - "chalk": "~1.1.3", "gulp": "3.9.1", "gulp-livereload": "~3.8.1", "gulp-nodemon": "~2.2.1", diff --git a/server/generate/index.js b/server/generate/index.js new file mode 100644 index 0000000..0fb654b --- /dev/null +++ b/server/generate/index.js @@ -0,0 +1,83 @@ +const path = require('path'); +const fs = require('fs-extra'); +const inquirer = require('inquirer'); +const latestVersion = require('latest-version'); + +const onError = e => console.error(e); +const neededPackages = ['uizoo']; +const uiZooScript = 'TODO script here'; + +/** + * Questions: + * #1 Provide a glob to your components (default: '*'): + */ +const globPromptName = 'glob'; +const questions = [ + { + name: globPromptName, + message: 'Provide a glob to find your components, default is all files:', + default: path.join('**','*') + } +]; + +function generate() { + inquirer.prompt(questions) + .then(copyTemplates) + .then(executeCommands) + .catch(onError); +} + +function copyTemplates(answers) { + return new Promise((resolve, reject) => { + return updatePackageJson() + .then(p => console.log(p)) + .then(() => resolve()) + .catch(reject); + }); +} + +function executeCommands() { + return new Promise((resolve, reject) => { + resolve(); + }); +} + +function updatePackageJson() { + return new Promise((resolve, reject) => { + const pkgPath = path.resolve('package.json'); + const defaultPkgPath = path.join(__dirname, 'templates','package.json'); + + fs.exists(pkgPath) + .then(exists => fs.readFile(exists ? pkgPath : defaultPkgPath)) + .then(modifyPackage) + .then(pkg => fs.writeFile(pkgPath, pkg)) + .then(resolve) + .catch(reject); + }); +} + +function modifyPackage(packageBuffer) { + return new Promise((resolve, reject) => { + Promise.all(neededPackages.map(p => latestVersion(p))) + .then((neededPackagesVersions) => { + let pkg = JSON.parse(packageBuffer.toString()); + // Add dependencies + neededPackages.forEach((neededPackage, i) => { + if((!pkg.dependencies || !pkg.dependencies[neededPackage]) && + (!pkg.devDependencies || !pkg.devDependencies[neededPackage])) { + pkg.devDependencies = Object.assign({}, pkg.devDependencies, { + [neededPackage]: `~${neededPackagesVersions[i]}` + }); + } + }); + // Add scripts + pkg.scripts = Object.assign({}, pkg.scripts, { + "uizoo": uiZooScript + }); + resolve(JSON.stringify(pkg)); + }) + .catch(reject); + }); +} + +module.exports = generate; \ No newline at end of file diff --git a/server/generate/templates/package.json b/server/generate/templates/package.json new file mode 100644 index 0000000..2ab2edd --- /dev/null +++ b/server/generate/templates/package.json @@ -0,0 +1,4 @@ +{ + "name": "uizoo-app", + "version": "1.0.0" +} \ No newline at end of file diff --git a/server/logo.js b/server/logo.js new file mode 100644 index 0000000..241834c --- /dev/null +++ b/server/logo.js @@ -0,0 +1,11 @@ +module.exports = ` +___/\\\\\\________/\\\\\\________/\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\_____________________________ +___\\/\\\\\\_______\\/\\\\\\_______\\////////////\\\\\\______________________________ +____\\/\\\\\\_______\\/\\\\\\__/\\\\\\___________/\\\\\\/_______________________________ +_____\\/\\\\\\_______\\/\\\\\\_\\///__________/\\\\\\/_________/\\\\\\\\\\________/\\\\\\\\\\____ +______\\/\\\\\\_______\\/\\\\\\__/\\\\\\_______/\\\\\\/_________/\\\\\\///\\\\\\____/\\\\\\///\\\\\\__ +_______\\/\\\\\\_______\\/\\\\\\_\\/\\\\\\_____/\\\\\\/__________/\\\\\\__\\//\\\\\\__/\\\\\\__\\//\\\\\\_ +________\\//\\\\\\______/\\\\\\__\\/\\\\\\___/\\\\\\/___________\\//\\\\\\__/\\\\\\__\\//\\\\\\__/\\\\\\__ +__________\\///\\\\\\\\\\\\\\\\\\/___\\/\\\\\\__/\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\__\\///\\\\\\\\\\/____\\///\\\\\\\\\\/___ +_____________\\/////////_____\\///__\\///////////////_____\\/////________\\/////_____ +`; \ No newline at end of file diff --git a/server/server.js b/server/server.js index af2b0bb..6f9f424 100644 --- a/server/server.js +++ b/server/server.js @@ -1,7 +1,6 @@ let compression = require('compression'); let cors = require('cors'); let express = require('express'); -let helmet = require('helmet'); let http = require('http'); let {json} = require('body-parser'); let path = require('path'); @@ -22,7 +21,6 @@ module.exports = function (app) { */ function useDependencies(app) { app.use(json()); - app.use(helmet()); app.use(compression({ level: 1 })); @@ -34,7 +32,6 @@ function useDependencies(app) { */ function start(app) { let rootDir = getRootDir(__dirname); - // app.set('view engine', 'jade'); app.set('port', (process.env.PORT || 5000)); app.use('/dist', express.static(path.join(rootDir, 'dist'))); From a3f2fd749c92b56e3d63191d0d8a12cd0e48d436 Mon Sep 17 00:00:00 2001 From: Noam Elboim Date: Thu, 12 Oct 2017 01:39:18 +0300 Subject: [PATCH 02/12] creating a webpack config for the web server --- bin/uizoo.js | 2 +- client/services/compileWithContext.js | 2 +- package.json | 14 ++--- server/generate/index.js | 70 ++++++++++++++-------- server/generate/templates/index.html | 13 ++++ server/generate/templates/index.js | 5 ++ server/generate/templates/webpack.uizoo.js | 70 ++++++++++++++++++++++ 7 files changed, 142 insertions(+), 34 deletions(-) create mode 100644 server/generate/templates/index.html create mode 100644 server/generate/templates/index.js create mode 100644 server/generate/templates/webpack.uizoo.js diff --git a/bin/uizoo.js b/bin/uizoo.js index 1b743e2..954f81f 100644 --- a/bin/uizoo.js +++ b/bin/uizoo.js @@ -2,7 +2,7 @@ const chalk = require('chalk'); const logo = require('../server/logo'); -const log = console.log; +const log = console.log.bind(console); log(` Welcome to the ~ diff --git a/client/services/compileWithContext.js b/client/services/compileWithContext.js index 5dd0c3c..5dd9b9a 100644 --- a/client/services/compileWithContext.js +++ b/client/services/compileWithContext.js @@ -1,6 +1,6 @@ import React from 'react'; import _ from 'underscore'; -import Babel from 'babel-standalone'; +import * as Babel from 'babel-standalone'; export function createCompiler(context) { const iframe = createIframe(); diff --git a/package.json b/package.json index 8123c15..098bf9c 100644 --- a/package.json +++ b/package.json @@ -30,16 +30,11 @@ }, "dependencies": { "babel-standalone": "~6.25.0", - "body-parser": "~1.15.2", "chalk": "~1.1.3", - "compression": "~1.6.2", - "cors": "~2.8.3", "doctrine-standalone": "~1.0.0", - "express": "~4.15.2", "fs-extra": "~4.0.2", - "glob": "7.0.6", - "inquirer": "~3.3.0", - "latest-version": "^3.1.0", + "latest-version": "~3.1.0", + "opn": "~5.1.0", "react": "~16.0.0", "react-dom": "~16.0.0", "react-router-dom": "~4.2.2", @@ -50,6 +45,11 @@ }, "license": "MIT", "devDependencies": { + "body-parser": "~1.15.2", + "compression": "~1.6.2", + "cors": "~2.8.3", + "express": "~4.15.2", + "glob": "7.0.6", "gulp": "3.9.1", "gulp-livereload": "~3.8.1", "gulp-nodemon": "~2.2.1", diff --git a/server/generate/index.js b/server/generate/index.js index 0fb654b..430f61d 100644 --- a/server/generate/index.js +++ b/server/generate/index.js @@ -1,51 +1,71 @@ const path = require('path'); +const {spawn} = require('child_process'); const fs = require('fs-extra'); -const inquirer = require('inquirer'); const latestVersion = require('latest-version'); +const opn = require('opn'); const onError = e => console.error(e); -const neededPackages = ['uizoo']; -const uiZooScript = 'TODO script here'; +const log = console.log.bind(console); +const getTemplatePath = fileName => path.join(__dirname, 'templates', fileName); -/** - * Questions: - * #1 Provide a glob to your components (default: '*'): - */ -const globPromptName = 'glob'; -const questions = [ - { - name: globPromptName, - message: 'Provide a glob to find your components, default is all files:', - default: path.join('**','*') - } +const neededPackages = [ + 'uizoo', + 'webpack', + 'webpack-dev-server', + 'cache-loader', + 'babel-loader', + 'babel-preset-env', + 'babel-preset-react', + 'babel-plugin-transform-object-rest-spread', + 'babel-plugin-syntax-dynamic-import' ]; +const templatesToCopy = [ + 'index.html', + 'index.js', + 'webpack.uizoo.js' +]; + +const appFolder = path.resolve('uizoo-app'); +const uiZooScript = `node ${path.join('uizoo-app', 'webpack.uizoo.js')}`; + function generate() { - inquirer.prompt(questions) - .then(copyTemplates) - .then(executeCommands) - .catch(onError); + log(' ~ Copying templates...'); + copyTemplates() + .then(() => log(' ~ Executing commands...')) + .then(() => execCmd('npm i')) + .then(() => {setTimeout(() => opn('http://localhost:5005/uizoo'), 2500)}) + .then(() => execCmd('npm run uizoo', true)) + .then(() => process.exit(0)) + .catch(onError); } -function copyTemplates(answers) { +function copyTemplates() { return new Promise((resolve, reject) => { return updatePackageJson() - .then(p => console.log(p)) - .then(() => resolve()) + .then(() => fs.ensureDir(appFolder)) + .then(() => Promise.all(templatesToCopy.map(copyTemplate))) + .then(resolve) .catch(reject); }); } -function executeCommands() { +function copyTemplate(templateName) { + return fs.copy(getTemplatePath(templateName), path.join(appFolder, templateName)); +} + +function execCmd(cmd) { return new Promise((resolve, reject) => { - resolve(); + let cmdParts = cmd.split(' '); + const ls = spawn(cmdParts.shift(), [].concat(cmdParts), {stdio: "inherit"}); + ls.on('close', resolve); }); } function updatePackageJson() { return new Promise((resolve, reject) => { const pkgPath = path.resolve('package.json'); - const defaultPkgPath = path.join(__dirname, 'templates','package.json'); + const defaultPkgPath = getTemplatePath('package.json'); fs.exists(pkgPath) .then(exists => fs.readFile(exists ? pkgPath : defaultPkgPath)) @@ -58,7 +78,7 @@ function updatePackageJson() { function modifyPackage(packageBuffer) { return new Promise((resolve, reject) => { - Promise.all(neededPackages.map(p => latestVersion(p))) + Promise.all(neededPackages.map(latestVersion)) .then((neededPackagesVersions) => { let pkg = JSON.parse(packageBuffer.toString()); // Add dependencies diff --git a/server/generate/templates/index.html b/server/generate/templates/index.html new file mode 100644 index 0000000..7110a54 --- /dev/null +++ b/server/generate/templates/index.html @@ -0,0 +1,13 @@ + + + + + UiZoo + + + + + + + + \ No newline at end of file diff --git a/server/generate/templates/index.js b/server/generate/templates/index.js new file mode 100644 index 0000000..345c8af --- /dev/null +++ b/server/generate/templates/index.js @@ -0,0 +1,5 @@ +import UiZoo from 'uizoo'; + +let root = document.createElement('div'); +document.body.appendChild(root); +UiZoo.init(undefined, undefined, root, '/uizoo/'); \ No newline at end of file diff --git a/server/generate/templates/webpack.uizoo.js b/server/generate/templates/webpack.uizoo.js new file mode 100644 index 0000000..be4f5b2 --- /dev/null +++ b/server/generate/templates/webpack.uizoo.js @@ -0,0 +1,70 @@ +const path = require('path'); +const WebpackDevServer = require('webpack-dev-server'); +const webpack = require('webpack'); +const express = require('express'); + +const SERVER_PORT = 5005; +const componentsRoot = path.dirname(__dirname); + +const webpackConfig = { + entry: { + app: [path.join(__dirname, 'index.js')], + }, + output: { + filename: 'components.js', + path: __dirname, + publicPath: path.sep, + }, + module: { + rules: [ + { + test: /\.js$/, + exclude: /node_modules.*/, + use: [ + { + loader: require.resolve('babel-loader'), + options: { + presets: [ + require.resolve('babel-preset-env'), + require.resolve('babel-preset-react') + ], + plugins: [ + require.resolve('babel-plugin-transform-object-rest-spread'), + require.resolve('babel-plugin-syntax-dynamic-import') + ], + } + }, + ], + }, + ] + }, +}; + +// Addition to the config for the web dev server +webpackConfig.entry.app.push(`webpack-dev-server/client?http://localhost:${SERVER_PORT}/`, "webpack/hot/dev-server"); +webpackConfig.plugins = [].concat(webpackConfig.plugins || [], [ + new webpack.HotModuleReplacementPlugin() +]); +webpackConfig.devServer = { + inline: true, + hot: true +}; + +const server = new WebpackDevServer(webpack(webpackConfig), { + contentBase: 'uizoo-app/', + hot: true, + noInfo: true, + before: (app) => { + app.use('[/]', (req, res) => { + res.redirect('/uizoo'); + }); + app.use(express.static(componentsRoot)); + app.all('/uizoo*', (req, res) => { + res.sendFile('index.html', {root: __dirname}); + }); + }, +}); + +server.listen(SERVER_PORT, 'localhost', () => { + console.log(` +*+*+ UiZoo on localhost:${SERVER_PORT} +*+*+`); +}); \ No newline at end of file From a063bc17121a9840617199e39bb7aafa6d215847 Mon Sep 17 00:00:00 2001 From: Noam Elboim Date: Thu, 12 Oct 2017 12:35:32 +0300 Subject: [PATCH 03/12] creating config files creations script --- server/generate/index.js | 6 +- .../generate/templates/componentsContainer.js | 1 + server/generate/templates/config.js | 42 +++++ .../generate/templates/createConfigsScript.js | 178 ++++++++++++++++++ .../templates/documentationContainer.js | 1 + server/generate/templates/index.js | 5 +- server/generate/templates/package.json | 7 +- server/generate/templates/webpack.uizoo.js | 51 +++-- 8 files changed, 271 insertions(+), 20 deletions(-) create mode 100644 server/generate/templates/componentsContainer.js create mode 100644 server/generate/templates/config.js create mode 100644 server/generate/templates/createConfigsScript.js create mode 100644 server/generate/templates/documentationContainer.js diff --git a/server/generate/index.js b/server/generate/index.js index 430f61d..c2055ad 100644 --- a/server/generate/index.js +++ b/server/generate/index.js @@ -23,7 +23,11 @@ const neededPackages = [ const templatesToCopy = [ 'index.html', 'index.js', - 'webpack.uizoo.js' + 'webpack.uizoo.js', + 'createConfigsScript.js', + 'componentsContainer.js', + 'documentationContainer.js', + 'config.js', ]; const appFolder = path.resolve('uizoo-app'); diff --git a/server/generate/templates/componentsContainer.js b/server/generate/templates/componentsContainer.js new file mode 100644 index 0000000..4b0f9fb --- /dev/null +++ b/server/generate/templates/componentsContainer.js @@ -0,0 +1 @@ +export default null; \ No newline at end of file diff --git a/server/generate/templates/config.js b/server/generate/templates/config.js new file mode 100644 index 0000000..66ea8e1 --- /dev/null +++ b/server/generate/templates/config.js @@ -0,0 +1,42 @@ +const path = require('path'); + +/** + * Dev Server port + */ +const serverPort = 5005; + +/** + * The dir where the original command to create UiZoo was originated from, + * it is where the node_modules are and where to look for components from + */ +const componentsRootDir = path.dirname(__dirname); + +/** + * Glob to fetch all components for UiZoo + * It exclude node_modules & uizoo-app directories + * If you have a specific convention to your Components names, or specific sub-libraries, you should add it + */ +const componentsGlob = [...componentsRootDir.split(path.sep), '!(node_modules|uizoo-app)', '**', '*.js'].join('/'); + +/** + * Add this tag to a component JSDoc will exclude it from the config files of UiZoo + * @example + * This will exclude this component: + * @componentLibraryIgnore + */ +const ignoreTag = 'componentLibraryIgnore'; + +/** + * Strategy to decide on the file's JSDoc by a regex + * It will take the first JSDoc comment answering this regex + * It should have either a @description or @example tag in it + */ +const componentMainCommentRegex = /\/\*\*(\s*\*\s*.*?)*@(description|example).*(\s*\*.*)*/g; + +module.exports = { + serverPort, + componentsRootDir, + componentsGlob, + ignoreTag, + componentMainCommentRegex, +}; \ No newline at end of file diff --git a/server/generate/templates/createConfigsScript.js b/server/generate/templates/createConfigsScript.js new file mode 100644 index 0000000..e0ed394 --- /dev/null +++ b/server/generate/templates/createConfigsScript.js @@ -0,0 +1,178 @@ +const glob = require('glob'); +const path = require('path'); +const fs = require('fs-extra'); +const doctrine = require('doctrine'); + +const { + ignoreTag, + componentMainCommentRegex, + componentsGlob, + componentsRootDir +} = require('./config'); + +module.exports = createConfigs; + +/** + * Create 2 config files + * One is a mapping between components names to actual components + * and another is a mapping between components names to their documentation + * @return {Promise} + */ +function createConfigs() { + return new Promise((resolve, reject) => { + glob(componentsGlob, (err, filePaths = []) => { + if (err) return reject(err); + + Promise.all(filePaths.map(filePath => fs.readFile(filePath))) + .then((filesData) => processFiles(filesData, filePaths)) + .then(writeFiles) + .then(resolve) + .catch(reject); + + }); + }); +} + +/** + * Process components files and output a map that we can write to files + * @param {Array} filesData + * @param {Array} filePaths + * @return {Map} of component name to an object in the form {filePath, comment} + */ +function processFiles(filesData = [], filePaths = []) { + let componentsMap = new Map(); + + filesData.forEach((fileDataBuffer, i) => { + const fileData = fileDataBuffer.toString(); + // Get component main comment + const matches = fileData.match(componentMainCommentRegex); + if (matches && matches.length) { + // Choosing the first comment that matched the regex + let comment = matches[0], + filePath = filePaths[i]; + + const parsedComment = parseCommentToObject(comment); + // skip this components if it have an ignore tag + if (!parsedComment[ignoreTag]) { + const componentName = getComponentName(parsedComment, filePath); + componentsMap.set(componentName, {filePath, comment}); + } + } + }); + + return componentsMap; +} + +/** + * Write the map data to files + * It will sort the component names + * It will skip the writing if there is nothing to write or nothing had changed + * + * @param {Map} componentsMap + * @return {Promise} + */ +function writeFiles(componentsMap) { + let componentsKeys = [...componentsMap.keys()]; + if (!componentsKeys.length) return null; + let docMap = new Map(), + comMap = new Map(); + + componentsKeys.sort(); + componentsKeys.forEach(componentName => { + let componentConf = componentsMap.get(componentName); + docMap.set(componentName, componentConf.comment); + comMap.set(componentName, componentConf.filePath); + }); + + return Promise.all([ + writeIfDifferent('documentationContainer.js', createDocumentationFile(docMap)), + writeIfDifferent('componentsContainer.js', createComponentsFile(comMap)) + ]); +} + +/** + * Strategy to figure out the component name + * + * @param {Object} parsedComment + * @param {String} filePath + */ +function getComponentName(parsedComment, filePath) { + let name; + if (parsedComment.name && parsedComment.name[0] && parsedComment.name[0].name) { + // Option 1: name in JSDoc @name tag + name = parsedComment.name[0].name; + } else { + let fileParts = path.parse(filePath) || {}; + if (fileParts.name && !(/^index/.test(fileParts.name))) { + // Option 2: try to get name from file name, but make sure it's not index.~ something + name = fileParts.name; + } else { + // Option 3: nothing left - take dir name + name = path.basename(fileParts.dir); // parent's directory + } + } + return name; +} + +/** + * Create the documentation file from the map + * @param {Map} docMap + * @return {String} + */ +function createDocumentationFile(docMap) { + let docFile = 'export default {\n'; + for (let [componentName, comment] of docMap) { + // escaping ` and ${} by \` and \${} + docFile += `${componentName}: \`${comment.replace('`', '\\`').replace('${', '\\${')}\`,\n`; + } + docFile += '}'; + return docFile; +} + +/** + * Create the components file from the map + * @param {Map} comMap + * @return {String} + */ +function createComponentsFile(comMap) { + let comFile = '', + exportLine = 'export default {\n'; + for (let [componentName, filePath] of comMap) { + comFile += `import ${componentName} from '${filePath.replace(componentsRootDir, '..')}';\n`; + exportLine += ` ${componentName},\n`; + } + comFile += `${exportLine}};`; + return comFile; +} + +/** + * Write only if current content is different to prevent + * @param {String} fileName + * @param {String} fileContent + * @return {Promise} + */ +function writeIfDifferent(fileName, fileContent) { + const filePath = path.join(componentsRootDir, 'uizoo-app', fileName); + return new Promise((resolve, reject) => { + fs.readFile(filePath) + .then(fileBuffer => fileContent !== fileBuffer.toString()) + .then(shouldWrite => shouldWrite ? fs.writeFile(filePath, fileContent) : true) + .then(resolve) + .catch(reject); + }); +} + +/** + * Us doctrine to transform String comment to an Object + * @param {String} comment + * @return {Object} + */ +function parseCommentToObject(comment) { + const {tags = []} = doctrine.parse(comment, {unwrap: true, recoverable: true, sloppy: true}); + let doc = {}; + tags.forEach(tag => { + doc[tag.title] = doc[tag.title] || []; + doc[tag.title].push(tag); + }); + return doc; +} \ No newline at end of file diff --git a/server/generate/templates/documentationContainer.js b/server/generate/templates/documentationContainer.js new file mode 100644 index 0000000..4b0f9fb --- /dev/null +++ b/server/generate/templates/documentationContainer.js @@ -0,0 +1 @@ +export default null; \ No newline at end of file diff --git a/server/generate/templates/index.js b/server/generate/templates/index.js index 345c8af..24db903 100644 --- a/server/generate/templates/index.js +++ b/server/generate/templates/index.js @@ -1,5 +1,8 @@ import UiZoo from 'uizoo'; +import documentation from './documentationContainer'; +import components from './componentsContainer'; let root = document.createElement('div'); document.body.appendChild(root); -UiZoo.init(undefined, undefined, root, '/uizoo/'); \ No newline at end of file + +UiZoo.init(documentation, components, root, '/uizoo/'); \ No newline at end of file diff --git a/server/generate/templates/package.json b/server/generate/templates/package.json index 2ab2edd..713c267 100644 --- a/server/generate/templates/package.json +++ b/server/generate/templates/package.json @@ -1,4 +1,9 @@ { "name": "uizoo-app", - "version": "1.0.0" + "version": "1.0.0", + "description": "UiZoo - Dynamic React components library", + "repository": { + "url": "https://github.com/myheritage/UiZoo.js" + }, + "license": "MIT" } \ No newline at end of file diff --git a/server/generate/templates/webpack.uizoo.js b/server/generate/templates/webpack.uizoo.js index be4f5b2..a0dda17 100644 --- a/server/generate/templates/webpack.uizoo.js +++ b/server/generate/templates/webpack.uizoo.js @@ -2,18 +2,20 @@ const path = require('path'); const WebpackDevServer = require('webpack-dev-server'); const webpack = require('webpack'); const express = require('express'); +const createConfigs = require('./createConfigsScript'); +const {serverPort, componentsRootDir} = require('./config'); -const SERVER_PORT = 5005; -const componentsRoot = path.dirname(__dirname); - +/** + * Just a simple webpack config, you can replace or extend it + */ const webpackConfig = { entry: { - app: [path.join(__dirname, 'index.js')], + app: [path.join(__dirname, 'index.js')] }, output: { filename: 'components.js', path: __dirname, - publicPath: path.sep, + publicPath: path.sep }, module: { rules: [ @@ -33,17 +35,32 @@ const webpackConfig = { require.resolve('babel-plugin-syntax-dynamic-import') ], } - }, - ], - }, + } + ] + } ] - }, + } }; +/** + * Plugin to create the UiZoo config on each file change while using the webpack dev server + * @class GenerateUiZooConfigsPlugin + */ +class GenerateUiZooConfigsPlugin { + apply(compiler) { + compiler.plugin('watch-run', (c, cb) => { + createConfigs() + .then(() => cb()) + .catch(e => console.error(e)); + }); + } +} + // Addition to the config for the web dev server -webpackConfig.entry.app.push(`webpack-dev-server/client?http://localhost:${SERVER_PORT}/`, "webpack/hot/dev-server"); +webpackConfig.entry.app.push(`webpack-dev-server/client?http://localhost:${serverPort}/`, "webpack/hot/dev-server"); webpackConfig.plugins = [].concat(webpackConfig.plugins || [], [ - new webpack.HotModuleReplacementPlugin() + new webpack.HotModuleReplacementPlugin(), + new GenerateUiZooConfigsPlugin() ]); webpackConfig.devServer = { inline: true, @@ -55,16 +72,16 @@ const server = new WebpackDevServer(webpack(webpackConfig), { hot: true, noInfo: true, before: (app) => { - app.use('[/]', (req, res) => { + app.use('[/]', (req, res) => { // redirect on exact '/' url res.redirect('/uizoo'); }); - app.use(express.static(componentsRoot)); - app.all('/uizoo*', (req, res) => { + app.use(express.static(componentsRootDir)); + app.all('/uizoo*', (req, res) => { // this is needed for the client router to work res.sendFile('index.html', {root: __dirname}); }); - }, + } }); -server.listen(SERVER_PORT, 'localhost', () => { - console.log(` +*+*+ UiZoo on localhost:${SERVER_PORT} +*+*+`); +server.listen(serverPort, 'localhost', () => { + console.log(` +*+*+ UiZoo on localhost:${serverPort} +*+*+`); }); \ No newline at end of file From af8a8b0ac5a78ae5dd3e25c2c0ab6edf1377c127 Mon Sep 17 00:00:00 2001 From: Noam Elboim Date: Thu, 12 Oct 2017 19:32:59 +0300 Subject: [PATCH 04/12] improving code and adding documentation --- server/generate/config.js | 38 +++++++ server/generate/index.js | 110 +++------------------ server/generate/packageJsonService.js | 55 +++++++++++ server/generate/processService.js | 21 ++++ server/generate/templates/config.js | 6 +- server/generate/templates/webpack.uizoo.js | 79 +++++++++++---- server/generate/templatesService.js | 20 ++++ 7 files changed, 212 insertions(+), 117 deletions(-) create mode 100644 server/generate/config.js create mode 100644 server/generate/packageJsonService.js create mode 100644 server/generate/processService.js create mode 100644 server/generate/templatesService.js diff --git a/server/generate/config.js b/server/generate/config.js new file mode 100644 index 0000000..fc5b8b0 --- /dev/null +++ b/server/generate/config.js @@ -0,0 +1,38 @@ +const path = require('path'); + +const appFolderPath = path.resolve('uizoo-app'); +const uiZooScript = `node ${path.join('uizoo-app', 'webpack.uizoo.js')}`; + +const neededPackages = [ + 'uizoo', + 'webpack', + 'webpack-dev-server', + 'babel-loader', + 'babel-preset-env', + 'babel-preset-react', + 'babel-plugin-transform-object-rest-spread', + 'babel-plugin-syntax-dynamic-import', + 'style-loader', + 'css-loader', + 'fs-extra' +]; + +const templatesToCopy = [ + 'index.html', + 'index.js', + 'webpack.uizoo.js', + 'createConfigsScript.js', + 'componentsContainer.js', + 'documentationContainer.js', + 'config.js', +]; + +const log = console.log.bind(console); + +module.exports = { + appFolderPath, + uiZooScript, + neededPackages, + templatesToCopy, + log +}; \ No newline at end of file diff --git a/server/generate/index.js b/server/generate/index.js index c2055ad..9a7214c 100644 --- a/server/generate/index.js +++ b/server/generate/index.js @@ -1,107 +1,23 @@ -const path = require('path'); -const {spawn} = require('child_process'); const fs = require('fs-extra'); -const latestVersion = require('latest-version'); const opn = require('opn'); -const onError = e => console.error(e); -const log = console.log.bind(console); -const getTemplatePath = fileName => path.join(__dirname, 'templates', fileName); - -const neededPackages = [ - 'uizoo', - 'webpack', - 'webpack-dev-server', - 'cache-loader', - 'babel-loader', - 'babel-preset-env', - 'babel-preset-react', - 'babel-plugin-transform-object-rest-spread', - 'babel-plugin-syntax-dynamic-import' -]; - -const templatesToCopy = [ - 'index.html', - 'index.js', - 'webpack.uizoo.js', - 'createConfigsScript.js', - 'componentsContainer.js', - 'documentationContainer.js', - 'config.js', -]; - -const appFolder = path.resolve('uizoo-app'); -const uiZooScript = `node ${path.join('uizoo-app', 'webpack.uizoo.js')}`; +const {updatePackageJson} = require('./packageJsonService'); +const {copyTemplate} = require('./templatesService'); +const {executeCommand} = require('./processService'); +const {log, templatesToCopy, appFolderPath} = require('./config'); function generate() { - log(' ~ Copying templates...'); - copyTemplates() - .then(() => log(' ~ Executing commands...')) - .then(() => execCmd('npm i')) + log(' ~ Copying templates...\n'); + updatePackageJson() + .then(() => fs.ensureDir(appFolderPath)) + .then(() => Promise.all(templatesToCopy.map(copyTemplate))) + .then(() => log(' ~ Executing commands...\n')) + .then(() => executeCommand('npm i')) .then(() => {setTimeout(() => opn('http://localhost:5005/uizoo'), 2500)}) - .then(() => execCmd('npm run uizoo', true)) + .then(() => log(' ~ Done! Executing `uizoo` script:\n')) + .then(() => executeCommand('npm run uizoo')) .then(() => process.exit(0)) - .catch(onError); -} - -function copyTemplates() { - return new Promise((resolve, reject) => { - return updatePackageJson() - .then(() => fs.ensureDir(appFolder)) - .then(() => Promise.all(templatesToCopy.map(copyTemplate))) - .then(resolve) - .catch(reject); - }); -} - -function copyTemplate(templateName) { - return fs.copy(getTemplatePath(templateName), path.join(appFolder, templateName)); -} - -function execCmd(cmd) { - return new Promise((resolve, reject) => { - let cmdParts = cmd.split(' '); - const ls = spawn(cmdParts.shift(), [].concat(cmdParts), {stdio: "inherit"}); - ls.on('close', resolve); - }); -} - -function updatePackageJson() { - return new Promise((resolve, reject) => { - const pkgPath = path.resolve('package.json'); - const defaultPkgPath = getTemplatePath('package.json'); - - fs.exists(pkgPath) - .then(exists => fs.readFile(exists ? pkgPath : defaultPkgPath)) - .then(modifyPackage) - .then(pkg => fs.writeFile(pkgPath, pkg)) - .then(resolve) - .catch(reject); - }); -} - -function modifyPackage(packageBuffer) { - return new Promise((resolve, reject) => { - Promise.all(neededPackages.map(latestVersion)) - .then((neededPackagesVersions) => { - let pkg = JSON.parse(packageBuffer.toString()); - // Add dependencies - neededPackages.forEach((neededPackage, i) => { - if((!pkg.dependencies || !pkg.dependencies[neededPackage]) && - (!pkg.devDependencies || !pkg.devDependencies[neededPackage])) { - pkg.devDependencies = Object.assign({}, pkg.devDependencies, { - [neededPackage]: `~${neededPackagesVersions[i]}` - }); - } - }); - // Add scripts - pkg.scripts = Object.assign({}, pkg.scripts, { - "uizoo": uiZooScript - }); - resolve(JSON.stringify(pkg)); - }) - .catch(reject); - }); + .catch(e => console.error(e)); } module.exports = generate; \ No newline at end of file diff --git a/server/generate/packageJsonService.js b/server/generate/packageJsonService.js new file mode 100644 index 0000000..041c0cc --- /dev/null +++ b/server/generate/packageJsonService.js @@ -0,0 +1,55 @@ +const path = require('path'); +const latestVersion = require('latest-version'); +const fs = require('fs-extra'); +const {resolveTemplatePath} = require('./templatesService'); +const {uiZooScript, neededPackages} = require('./config'); + +module.exports = { + updatePackageJson +}; + +/** + * Update the folder's package.json with needed dependencies or use a fresh one from templates + * if there is none + * @return {Promise} + */ +function updatePackageJson() { + return new Promise((resolve, reject) => { + const pkgPath = path.resolve('package.json'); + const defaultPkgPath = resolveTemplatePath('package.json'); + + fs.exists(pkgPath) + .then(exists => fs.readFile(exists ? pkgPath : defaultPkgPath)) + .then(modifyPackage) + .then(pkg => fs.writeFile(pkgPath, pkg)) + .then(resolve) + .catch(reject); + }); +} + +function modifyPackage(packageBuffer) { + return new Promise((resolve, reject) => { + Promise.all(neededPackages.map(latestVersion)) + .then(neededPackagesVersions => { + let pkg = JSON.parse(packageBuffer.toString()); + + // Add dependencies + neededPackages.forEach((neededPackage, i) => { + if((!pkg.dependencies || !pkg.dependencies[neededPackage]) && + (!pkg.devDependencies || !pkg.devDependencies[neededPackage])) { + + pkg.devDependencies = Object.assign({}, pkg.devDependencies, { + [neededPackage]: `~${neededPackagesVersions[i]}` + }); + } + }); + + // Add scripts + pkg.scripts = Object.assign({}, pkg.scripts, { + "uizoo": uiZooScript + }); + resolve(JSON.stringify(pkg)); + }) + .catch(reject); + }); +} \ No newline at end of file diff --git a/server/generate/processService.js b/server/generate/processService.js new file mode 100644 index 0000000..8ba6658 --- /dev/null +++ b/server/generate/processService.js @@ -0,0 +1,21 @@ +const {spawn} = require('child_process'); +const chalk = require('chalk'); +const {log} = require('./config'); + +module.exports = { + executeCommand +}; + +/** + * Execute a command to terminal with inherit io, resolve when it is done + * @param {String} cmd + * @return {Promise} + */ +function executeCommand(cmd) { + return new Promise((resolve, reject) => { + log(chalk.grey(` ${cmd}\n`)); + let cmdParts = cmd.split(' '); + const ls = spawn(cmdParts.shift(), [].concat(cmdParts), {stdio: "inherit"}); + ls.on('close', resolve); + }); +} \ No newline at end of file diff --git a/server/generate/templates/config.js b/server/generate/templates/config.js index 66ea8e1..d77044e 100644 --- a/server/generate/templates/config.js +++ b/server/generate/templates/config.js @@ -1,9 +1,11 @@ const path = require('path'); /** - * Dev Server port + * Dev Server config */ const serverPort = 5005; +const serverProtocol = process.env.HTTPS === 'true' ? 'https' : 'http'; +const serverHost = process.env.HOST || '0.0.0.0'; /** * The dir where the original command to create UiZoo was originated from, @@ -35,6 +37,8 @@ const componentMainCommentRegex = /\/\*\*(\s*\*\s*.*?)*@(description|example).*( module.exports = { serverPort, + serverProtocol, + serverHost, componentsRootDir, componentsGlob, ignoreTag, diff --git a/server/generate/templates/webpack.uizoo.js b/server/generate/templates/webpack.uizoo.js index a0dda17..af8f0f3 100644 --- a/server/generate/templates/webpack.uizoo.js +++ b/server/generate/templates/webpack.uizoo.js @@ -2,13 +2,20 @@ const path = require('path'); const WebpackDevServer = require('webpack-dev-server'); const webpack = require('webpack'); const express = require('express'); +const chalk = require('chalk'); const createConfigs = require('./createConfigsScript'); -const {serverPort, componentsRootDir} = require('./config'); +const { + serverPort, + serverHost, + serverProtocol, + componentsRootDir +} = require('./config'); /** * Just a simple webpack config, you can replace or extend it */ const webpackConfig = { + devtool: 'cheap-module-source-map', entry: { app: [path.join(__dirname, 'index.js')] }, @@ -20,25 +27,51 @@ const webpackConfig = { module: { rules: [ { - test: /\.js$/, + test: /\.(js|jsx)$/, exclude: /node_modules.*/, - use: [ - { - loader: require.resolve('babel-loader'), - options: { - presets: [ - require.resolve('babel-preset-env'), - require.resolve('babel-preset-react') - ], - plugins: [ - require.resolve('babel-plugin-transform-object-rest-spread'), - require.resolve('babel-plugin-syntax-dynamic-import') - ], - } + use: [{ + loader: require.resolve('babel-loader'), + options: { + babelrc: false, + presets: [ + require.resolve('babel-preset-env'), + require.resolve('babel-preset-react') + ], + plugins: [ + require.resolve('babel-plugin-transform-object-rest-spread'), + require.resolve('babel-plugin-syntax-dynamic-import') + ], + cacheDirectory: true } + }] + }, + { + test: /\.css$/, + use: [ + require.resolve('style-loader'), + require.resolve('css-loader'), + + /** + * To support scss/sass files - + * 1. un comment line below + * 2. run `npm i -D sass-loader node-sass-chokidar` + * 3. change the 'test' to `/\.scss$/` instead of the current `/\.css$/` + */ + // require.resolve('sass-loader') ] } ] + }, + // Mock node libs in case some npm pkg depend on them + node: { + dgram: 'empty', + fs: 'empty', + net: 'empty', + tls: 'empty', + child_process: 'empty' + }, + performance: { + hints: false } }; @@ -60,28 +93,36 @@ class GenerateUiZooConfigsPlugin { webpackConfig.entry.app.push(`webpack-dev-server/client?http://localhost:${serverPort}/`, "webpack/hot/dev-server"); webpackConfig.plugins = [].concat(webpackConfig.plugins || [], [ new webpack.HotModuleReplacementPlugin(), - new GenerateUiZooConfigsPlugin() + new GenerateUiZooConfigsPlugin(), + new webpack.NamedModulesPlugin() ]); webpackConfig.devServer = { inline: true, hot: true }; +// The Web Dev server const server = new WebpackDevServer(webpack(webpackConfig), { contentBase: 'uizoo-app/', hot: true, noInfo: true, + compress: true, + https: serverProtocol === 'https', + host: serverHost, before: (app) => { - app.use('[/]', (req, res) => { // redirect on exact '/' url + app.use('[/]', (req, res) => { // redirect on exact '/' url to /uizoo res.redirect('/uizoo'); }); app.use(express.static(componentsRootDir)); app.all('/uizoo*', (req, res) => { // this is needed for the client router to work - res.sendFile('index.html', {root: __dirname}); + res.sendFile('index.html', { + root: __dirname + }); }); } }); +let {cyan, grey} = chalk; server.listen(serverPort, 'localhost', () => { - console.log(` +*+*+ UiZoo on localhost:${serverPort} +*+*+`); + console.log(` ${grey(`+*+*+`)} ${chalk.cyan(`UiZoo up on localhost:${serverPort}`)} ${grey(`+*+*+`)}`); }); \ No newline at end of file diff --git a/server/generate/templatesService.js b/server/generate/templatesService.js new file mode 100644 index 0000000..110c14d --- /dev/null +++ b/server/generate/templatesService.js @@ -0,0 +1,20 @@ +const path = require('path'); +const fs = require('fs-extra'); +const {appFolderPath} = require('./config'); + +module.exports = { + copyTemplate, + resolveTemplatePath +}; + +/** + * Copy template from template folders to the new uizoo-app folder + * @param {String} templateName + * @return {Promise} + */ +function copyTemplate(templateName) { + return fs.copy(resolveTemplatePath(templateName), path.join(appFolderPath, templateName)); +} +function resolveTemplatePath(fileName) { + return path.join(__dirname, 'templates', fileName); +} \ No newline at end of file From 6d74fca655c66bf76cb740ad6fab471d46b47750 Mon Sep 17 00:00:00 2001 From: Noam Elboim Date: Thu, 12 Oct 2017 20:06:36 +0300 Subject: [PATCH 05/12] fixing comment escaping to be global --- server/generate/templates/createConfigsScript.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/generate/templates/createConfigsScript.js b/server/generate/templates/createConfigsScript.js index e0ed394..a9e3304 100644 --- a/server/generate/templates/createConfigsScript.js +++ b/server/generate/templates/createConfigsScript.js @@ -123,7 +123,7 @@ function createDocumentationFile(docMap) { let docFile = 'export default {\n'; for (let [componentName, comment] of docMap) { // escaping ` and ${} by \` and \${} - docFile += `${componentName}: \`${comment.replace('`', '\\`').replace('${', '\\${')}\`,\n`; + docFile += `${componentName}: \`${comment.replace(/\`/g, '\\`').replace(/\$\{/g, '\\${')}\`,\n`; } docFile += '}'; return docFile; From 322cd8942b1ee599bd78d95aa0e4e6b8cadd4d75 Mon Sep 17 00:00:00 2001 From: Noam Elboim Date: Thu, 12 Oct 2017 21:19:49 +0300 Subject: [PATCH 06/12] writing package.json as JSON with 2 spaces --- server/generate/packageJsonService.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/generate/packageJsonService.js b/server/generate/packageJsonService.js index 041c0cc..781c7f1 100644 --- a/server/generate/packageJsonService.js +++ b/server/generate/packageJsonService.js @@ -21,7 +21,7 @@ function updatePackageJson() { fs.exists(pkgPath) .then(exists => fs.readFile(exists ? pkgPath : defaultPkgPath)) .then(modifyPackage) - .then(pkg => fs.writeFile(pkgPath, pkg)) + .then(pkg => fs.writeJSON(pkgPath, pkg, {spaces: 2})) .then(resolve) .catch(reject); }); @@ -48,7 +48,7 @@ function modifyPackage(packageBuffer) { pkg.scripts = Object.assign({}, pkg.scripts, { "uizoo": uiZooScript }); - resolve(JSON.stringify(pkg)); + resolve(pkg); }) .catch(reject); }); From e159e29ef68e117b86dafda5f5762261b2f7241c Mon Sep 17 00:00:00 2001 From: Noam Elboim Date: Thu, 12 Oct 2017 21:54:41 +0300 Subject: [PATCH 07/12] fixing import missing of underscore --- client/Components/UI/Tooltip/UiTooltip/index.js | 1 + .../UI/Tooltip/autoLocationDetector/autoLocationDetector.js | 1 + 2 files changed, 2 insertions(+) diff --git a/client/Components/UI/Tooltip/UiTooltip/index.js b/client/Components/UI/Tooltip/UiTooltip/index.js index b1e68ac..7894f3b 100644 --- a/client/Components/UI/Tooltip/UiTooltip/index.js +++ b/client/Components/UI/Tooltip/UiTooltip/index.js @@ -1,4 +1,5 @@ import React from 'react'; +import _ from 'underscore'; import {SIDES, SIDE_TOP, ALIGNMENTS, ALIGNMENT_CENTER, TRIGGER_EVENTS, TRIGGER_EVENT_HOVER} from './constants'; import './index.scss'; diff --git a/client/Components/UI/Tooltip/autoLocationDetector/autoLocationDetector.js b/client/Components/UI/Tooltip/autoLocationDetector/autoLocationDetector.js index 416e859..bd80331 100644 --- a/client/Components/UI/Tooltip/autoLocationDetector/autoLocationDetector.js +++ b/client/Components/UI/Tooltip/autoLocationDetector/autoLocationDetector.js @@ -1,3 +1,4 @@ +import _ from 'underscore'; import { SIDE_TOP, SIDE_BOTTOM, From 19ee3b019778144025974e14172bf297b351be95 Mon Sep 17 00:00:00 2001 From: Noam Elboim Date: Thu, 12 Oct 2017 22:55:14 +0300 Subject: [PATCH 08/12] updating readme with CLI --- README.md | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index bab04f0..7950da0 100644 --- a/README.md +++ b/README.md @@ -17,32 +17,43 @@ This tool can be used for developing, for Product Managers to know what is possi ![React UiZoo 3](https://imgur.com/f3B2TDj.gif) ## How To UiZoo? -Git clone by: + +Just use our zero-configuration CLI! it's easy as pie! 🍽 + ``` -git clone git@github.com:myheritage/uizoo.js.git +npm i -g uizoo ``` -then + +In a directory, do: ``` -cd uizoo.js && npm i -gulp +uizoo ``` -This will start a server on http://localhost:5000 with the UiZoo -you can change the [components file](https://github.com/myheritage/uizoo.js/blob/master/client/components.js) and the [documentation file](https://github.com/myheritage/uizoo.js/blob/master/client/documentation.js) to start rapidly. -We recommend updating those files by a script automatically when files are changing (we plan to create plugins to help with this in the next future). -*or* npm install by: +It will create a [webpack development server](https://webpack.js.org/configuration/dev-server/) fully configured with [Hot Module Replacement](https://webpack.js.org/concepts/hot-module-replacement/) to watch your files while you develop! + +For example: + +![React UiZoo CLI](https://imgur.com/v3PbP8U.gif) + +Start the server with the newly added script: ``` -npm i -S uizoo +npm start uizoo ``` -then in your code, add: + +### Customization +The CLI creates a directory called `uizoo-app`, in it there is a file called `config.js` that determine basic stuff like the server's port, glob to find your components and more. There is also a very simple webpack configuration called `webpack.uizoo.js`. + + +### Local installation +*If you don't want to install UiZoo globally, you can instead do:* ``` -import 'uizoo/dist/index.css'; -import UiZoo from 'uizoo'; -UiZoo.init(documentation, components, rootElement); +npm i -D uizoo && ./node_modules/.bin/uizoo ``` -### init +### API ``` +import UiZoo from 'uizoo'; + UiZoo.init(documentation: Object, components: Object, rootElement: HTMLElement?, baseRoute: String?) ``` From 24e241974056e43ebfca93e6ddacfb9199a6d2e4 Mon Sep 17 00:00:00 2001 From: Noam Elboim Date: Thu, 12 Oct 2017 23:43:42 +0300 Subject: [PATCH 09/12] adding glob array functionallity --- server/generate/config.js | 3 +- server/generate/templates/config.js | 14 +++++- .../generate/templates/createConfigsScript.js | 44 ++++++++++++++----- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/server/generate/config.js b/server/generate/config.js index fc5b8b0..99b1e26 100644 --- a/server/generate/config.js +++ b/server/generate/config.js @@ -14,7 +14,8 @@ const neededPackages = [ 'babel-plugin-syntax-dynamic-import', 'style-loader', 'css-loader', - 'fs-extra' + 'fs-extra', + 'glob-stream' ]; const templatesToCopy = [ diff --git a/server/generate/templates/config.js b/server/generate/templates/config.js index d77044e..0af62b7 100644 --- a/server/generate/templates/config.js +++ b/server/generate/templates/config.js @@ -13,12 +13,24 @@ const serverHost = process.env.HOST || '0.0.0.0'; */ const componentsRootDir = path.dirname(__dirname); +/** + * TIL that glob use '/' separators everywhere! + */ +const componentsRootsDirGlob = path.sep === '\\' ? componentsRootDir.split(path.sep).join('/') : componentsRootDir; + /** * Glob to fetch all components for UiZoo * It exclude node_modules & uizoo-app directories * If you have a specific convention to your Components names, or specific sub-libraries, you should add it + * + * You can provide either a single glob or an array that will be aggregated + * (using 'glob-stream', so you can negate and stuff, see: https://github.com/gulpjs/glob-stream) */ -const componentsGlob = [...componentsRootDir.split(path.sep), '!(node_modules|uizoo-app)', '**', '*.js'].join('/'); +const componentsGlob = [ + `${componentsRootsDirGlob}/**/*.js`, + `!${componentsRootsDirGlob}/node_modules/**/*`, + `!${componentsRootsDirGlob}/uizoo-app/**/*`, +]; /** * Add this tag to a component JSDoc will exclude it from the config files of UiZoo diff --git a/server/generate/templates/createConfigsScript.js b/server/generate/templates/createConfigsScript.js index a9e3304..40224a2 100644 --- a/server/generate/templates/createConfigsScript.js +++ b/server/generate/templates/createConfigsScript.js @@ -1,4 +1,4 @@ -const glob = require('glob'); +const gs = require('glob-stream'); const path = require('path'); const fs = require('fs-extra'); const doctrine = require('doctrine'); @@ -19,18 +19,19 @@ module.exports = createConfigs; * @return {Promise} */ function createConfigs() { - return new Promise((resolve, reject) => { - glob(componentsGlob, (err, filePaths = []) => { - if (err) return reject(err); - - Promise.all(filePaths.map(filePath => fs.readFile(filePath))) - .then((filesData) => processFiles(filesData, filePaths)) - .then(writeFiles) - .then(resolve) - .catch(reject); + return promiseGlob(componentsGlob) + .then(filePaths => readFiles(filePaths) + .then(filesData => processFiles(filesData, filePaths)) + ) + .then(writeFiles); +} - }); - }); +/** + * @param {Array} filePaths + * @return {Promise} + */ +function readFiles(filePaths) { + return Promise.all(filePaths.map(filePath => fs.readFile(filePath))); } /** @@ -175,4 +176,23 @@ function parseCommentToObject(comment) { doc[tag.title].push(tag); }); return doc; +} + +/** + * Turn the glob stream to a promise that reslove the files + * @param {Array|String} globs + * @return {Promise} + */ +function promiseGlob(globs) { + return new Promise((resolve, reject) => { + let files = []; + let ls = gs(componentsGlob); + ls.on('data', (f = {}) => { + if (f.path) files.push(f.path); + }); + ls.on('error', reject); + ls.on('end', () => { + resolve(files); + }); + }); } \ No newline at end of file From 12cce4c1a1ed948696ae0f8b04be75f694e9d09a Mon Sep 17 00:00:00 2001 From: Noam Elboim Date: Fri, 13 Oct 2017 00:34:56 +0300 Subject: [PATCH 10/12] re-ordering directories --- Procfile | 2 +- bin/uizoo.js | 4 ++-- gulpfile.js | 6 +++--- {server => lib}/generate/config.js | 0 {server => lib}/generate/index.js | 0 {server => lib}/generate/packageJsonService.js | 0 {server => lib}/generate/processService.js | 0 {server => lib}/generate/templates/componentsContainer.js | 0 {server => lib}/generate/templates/config.js | 0 {server => lib}/generate/templates/createConfigsScript.js | 0 .../generate/templates/documentationContainer.js | 0 {server => lib}/generate/templates/index.html | 0 {server => lib}/generate/templates/index.js | 0 {server => lib}/generate/templates/package.json | 0 {server => lib}/generate/templates/webpack.uizoo.js | 0 {server => lib}/generate/templatesService.js | 0 {server => lib}/logo.js | 0 .../scripts/documentationMapper.js | 2 +- {server => lib/server}/main.js | 0 {server => lib/server}/server.js | 5 +---- 20 files changed, 8 insertions(+), 11 deletions(-) rename {server => lib}/generate/config.js (100%) rename {server => lib}/generate/index.js (100%) rename {server => lib}/generate/packageJsonService.js (100%) rename {server => lib}/generate/processService.js (100%) rename {server => lib}/generate/templates/componentsContainer.js (100%) rename {server => lib}/generate/templates/config.js (100%) rename {server => lib}/generate/templates/createConfigsScript.js (100%) rename {server => lib}/generate/templates/documentationContainer.js (100%) rename {server => lib}/generate/templates/index.html (100%) rename {server => lib}/generate/templates/index.js (100%) rename {server => lib}/generate/templates/package.json (100%) rename {server => lib}/generate/templates/webpack.uizoo.js (100%) rename {server => lib}/generate/templatesService.js (100%) rename {server => lib}/logo.js (100%) rename documentationMapper.js => lib/scripts/documentationMapper.js (97%) rename {server => lib/server}/main.js (100%) rename {server => lib/server}/server.js (90%) diff --git a/Procfile b/Procfile index 14ff2c2..15a371b 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: ./node_modules/.bin/rollup -c rollup-build.config.js -o dist/index.js -f iife -n UiZoo -g underscore:_,react:React,react-dom:ReactDOM,react-router-dom:ReactRouterDOM,doctrine:doctrine-standalone,babel-standalone:Babel && node server/main.js \ No newline at end of file +web: ./node_modules/.bin/rollup -c rollup-build.config.js -o dist/index.js -f iife -n UiZoo -g underscore:_,react:React,react-dom:ReactDOM,react-router-dom:ReactRouterDOM,doctrine:doctrine-standalone,babel-standalone:Babel && node lib/server/main.js \ No newline at end of file diff --git a/bin/uizoo.js b/bin/uizoo.js index 954f81f..207ce01 100644 --- a/bin/uizoo.js +++ b/bin/uizoo.js @@ -1,7 +1,7 @@ #!/usr/bin/env node const chalk = require('chalk'); -const logo = require('../server/logo'); +const logo = require('../lib/logo'); const log = console.log.bind(console); log(` @@ -9,4 +9,4 @@ Welcome to the ~ ${chalk.bold(chalk.cyan(logo))} `); -require('../server/generate')(); \ No newline at end of file +require('../lib/generate')(); \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 8df9afe..71f101c 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -2,7 +2,7 @@ let gulp = require('gulp'), rollup = require('rollup'), getRollupConfig = require('./rollup.config'), chalk = require('chalk'), - nodemon = require("gulp-nodemon"), + nodemon = require('gulp-nodemon'), livereload = require('gulp-livereload'), execSync = require("child_process").execSync; @@ -52,7 +52,7 @@ function bundleClient() { function startNodemonServer() { nodemonStream = nodemon({ - script: './server/main.js', + script: './lib/server/main.js', ext: 'js html', watch: false, }) @@ -78,7 +78,7 @@ function handleError(error) { function updateDocumentation() { try { - execSync(`node documentationMapper.js "./client/Components/UI/*/index.js" "./client/Components/UI/(.+)/index.js" "./client/documentation.js"`); + execSync(`node lib/scripts/documentationMapper.js "./client/Components/UI/*/index.js" "./client/Components/UI/(.+)/index.js" "./client/documentation.js"`); } catch (err) { console.error(err.message); diff --git a/server/generate/config.js b/lib/generate/config.js similarity index 100% rename from server/generate/config.js rename to lib/generate/config.js diff --git a/server/generate/index.js b/lib/generate/index.js similarity index 100% rename from server/generate/index.js rename to lib/generate/index.js diff --git a/server/generate/packageJsonService.js b/lib/generate/packageJsonService.js similarity index 100% rename from server/generate/packageJsonService.js rename to lib/generate/packageJsonService.js diff --git a/server/generate/processService.js b/lib/generate/processService.js similarity index 100% rename from server/generate/processService.js rename to lib/generate/processService.js diff --git a/server/generate/templates/componentsContainer.js b/lib/generate/templates/componentsContainer.js similarity index 100% rename from server/generate/templates/componentsContainer.js rename to lib/generate/templates/componentsContainer.js diff --git a/server/generate/templates/config.js b/lib/generate/templates/config.js similarity index 100% rename from server/generate/templates/config.js rename to lib/generate/templates/config.js diff --git a/server/generate/templates/createConfigsScript.js b/lib/generate/templates/createConfigsScript.js similarity index 100% rename from server/generate/templates/createConfigsScript.js rename to lib/generate/templates/createConfigsScript.js diff --git a/server/generate/templates/documentationContainer.js b/lib/generate/templates/documentationContainer.js similarity index 100% rename from server/generate/templates/documentationContainer.js rename to lib/generate/templates/documentationContainer.js diff --git a/server/generate/templates/index.html b/lib/generate/templates/index.html similarity index 100% rename from server/generate/templates/index.html rename to lib/generate/templates/index.html diff --git a/server/generate/templates/index.js b/lib/generate/templates/index.js similarity index 100% rename from server/generate/templates/index.js rename to lib/generate/templates/index.js diff --git a/server/generate/templates/package.json b/lib/generate/templates/package.json similarity index 100% rename from server/generate/templates/package.json rename to lib/generate/templates/package.json diff --git a/server/generate/templates/webpack.uizoo.js b/lib/generate/templates/webpack.uizoo.js similarity index 100% rename from server/generate/templates/webpack.uizoo.js rename to lib/generate/templates/webpack.uizoo.js diff --git a/server/generate/templatesService.js b/lib/generate/templatesService.js similarity index 100% rename from server/generate/templatesService.js rename to lib/generate/templatesService.js diff --git a/server/logo.js b/lib/logo.js similarity index 100% rename from server/logo.js rename to lib/logo.js diff --git a/documentationMapper.js b/lib/scripts/documentationMapper.js similarity index 97% rename from documentationMapper.js rename to lib/scripts/documentationMapper.js index 1025057..714cafb 100644 --- a/documentationMapper.js +++ b/lib/scripts/documentationMapper.js @@ -1,4 +1,4 @@ -// In next versions this service should be an optional plugin +// Internal script to generate UiZoo component's mapping to documentation function howToUse() { explanation = 'How to use: Run `node documentationMapper.js "./client/Components/UI/*/index.js" "./client/Components/UI/(.+)/index.js" "./client/documentation.js"`'; diff --git a/server/main.js b/lib/server/main.js similarity index 100% rename from server/main.js rename to lib/server/main.js diff --git a/server/server.js b/lib/server/server.js similarity index 90% rename from server/server.js rename to lib/server/server.js index 6f9f424..6af2fdf 100644 --- a/server/server.js +++ b/lib/server/server.js @@ -54,8 +54,5 @@ function start(app) { * @returns string */ function getRootDir(dirname) { - let paths = dirname.split(path.sep); - paths.splice(paths.length - 1); - dirname = paths.join(path.sep); - return dirname; + return path.dirname(path.dirname(__dirname)); } \ No newline at end of file From 149b3820a8bec633163e44a4f2cd018baac53421 Mon Sep 17 00:00:00 2001 From: Noam Elboim Date: Fri, 13 Oct 2017 01:25:53 +0300 Subject: [PATCH 11/12] re-orginzing rollup build --- Procfile | 2 +- client/index.js | 5 ++++- gulpfile.js | 13 +++---------- package.json | 5 ++++- rollup-build.config.js | 3 --- rollup.config.js | 42 +++++++++++++++++++++++++----------------- 6 files changed, 37 insertions(+), 33 deletions(-) delete mode 100644 rollup-build.config.js diff --git a/Procfile b/Procfile index 15a371b..e449d3d 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: ./node_modules/.bin/rollup -c rollup-build.config.js -o dist/index.js -f iife -n UiZoo -g underscore:_,react:React,react-dom:ReactDOM,react-router-dom:ReactRouterDOM,doctrine:doctrine-standalone,babel-standalone:Babel && node lib/server/main.js \ No newline at end of file +web: ./node_modules/.bin/rollup -c rollup.config.js -o dist/index.js -f iife -n UiZoo && node lib/server/main.js \ No newline at end of file diff --git a/client/index.js b/client/index.js index 4362f2e..4e4d2eb 100644 --- a/client/index.js +++ b/client/index.js @@ -1,6 +1,7 @@ import './index.scss'; import React from 'react'; import ReactDOM from 'react-dom'; +import _ from 'underscore'; import { BrowserRouter, Route } from 'react-router-dom'; import libraryData from './components'; @@ -9,7 +10,9 @@ import { checkDependencies } from './services/checkHealth'; import { createCompiler } from './services/compileWithContext'; import { parseDocumentation } from './services/parseDocumentation'; import App from './Components/App'; -import mapComponentsByModule from "./services/componentByModuleMapper"; +import mapComponentsByModule from './services/componentByModuleMapper'; + +window._extend = _.extend; // to be used instead of Object.assign const defaultRoot = document.getElementById('library-_-root'); diff --git a/gulpfile.js b/gulpfile.js index 71f101c..f55e4bd 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,6 +1,6 @@ let gulp = require('gulp'), rollup = require('rollup'), - getRollupConfig = require('./rollup.config'), + rConfig = require('./rollup.config'), chalk = require('chalk'), nodemon = require('gulp-nodemon'), livereload = require('gulp-livereload'), @@ -31,20 +31,13 @@ gulp.task("watch", () => { function bundleClient() { updateDocumentation(); - return rollup.rollup(getRollupConfig({external: ['underscore', 'react', 'react-dom', 'react-router-dom', 'doctrine-standalone', 'babel-standalone']})) + return rollup.rollup(rConfig) .then(bundle => { bundle.write({ format: 'iife', file: 'dist/index.js', - globals: { - 'underscore': '_', - 'react': 'React', - 'react-dom': 'ReactDOM', - 'react-router-dom':'ReactRouterDOM', - 'doctrine-standalone': 'doctrine', - 'babel-standalone': 'Babel', - }, name: 'UiZoo', + globals: rConfig.globals }); }) .catch(handleError); diff --git a/package.json b/package.json index 098bf9c..511bba2 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,10 @@ "description": "Dynamic React Component Library", "scripts": { "start": "npm run gulp:w", - "build": "rollup -c rollup-build.config.js -o dist/index.js -f iife -n UiZoo -g underscore:_,react:React,react-dom:ReactDOM,react-router-dom:ReactRouterDOM,doctrine-standalone:doctrine,babel-standalone:Babel && rollup -c rollup-build.config.js -o dist/index.cjs.js -f cjs -n UiZoo -g underscore:_,react:React,react-dom:ReactDOM,react-router-dom:ReactRouterDOM,doctrine-standalone:doctrine,babel-standalone:Babel && rollup -c rollup-build.config.js -o dist/index.es.js -f es -n UiZoo -g underscore:_,react:React,react-dom:ReactDOM,react-router-dom:ReactRouterDOM,doctrine-standalone:doctrine,babel-standalone:Babel", + "build": "npm run build:iife && npm run build:cjs && npm run build:es", + "build:iife": "./node_modules/.bin/rollup -c rollup.config.js -o dist/index.js -f iife -n UiZoo", + "build:cjs": "./node_modules/.bin/rollup -c rollup.config.js -o dist/index.cjs.js -f cjs -n UiZoo", + "build:es": "./node_modules/.bin/rollup -c rollup.config.js -o dist/index.es.js -f es -n UiZoo", "gulp:w": "gulp", "test": "npm start & SERVER_PID=$!; (cd tests; npm i && node run-tests.js); kill $SERVER_PID" }, diff --git a/rollup-build.config.js b/rollup-build.config.js deleted file mode 100644 index fb96285..0000000 --- a/rollup-build.config.js +++ /dev/null @@ -1,3 +0,0 @@ -const getRollupConfig = require('./rollup.config'); - -module.exports = getRollupConfig({external: ['underscore', 'react', 'react-dom', 'react-router-dom', 'doctrine-standalone', 'babel-standalone']}); \ No newline at end of file diff --git a/rollup.config.js b/rollup.config.js index acfeb23..d2242ee 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -11,9 +11,7 @@ let fs = require('fs'), comments = require('postcss-discard-comments'), dupes = require('postcss-discard-duplicates'), cssnext = require('postcss-cssnext'), - replace = require("rollup-plugin-replace"); - -const defaultExternal = []; + replace = require('rollup-plugin-replace'); function getPlugins({ external @@ -30,18 +28,9 @@ function getPlugins({ const defaultPlugins = [ json(), buble({ - objectAssign: 'Object.assign', - exclude: ["./node_modules/**/*"] + objectAssign: '_extend', + exclude: ['./node_modules/**/*'] }), - // babel({ - // presets: [ - // ["env", {modules: false}], - // "es2015-rollup", - // "react" - // ], - // exclude: "./node_modules/**/*" - // }), - nodeResolve({ browser: true, jsnext: true, @@ -49,7 +38,7 @@ function getPlugins({ }), commonjs(), replace({ - 'process.env.NODE_ENV': JSON.stringify('development') + 'process.env.NODE_ENV': JSON.stringify('production') }) ]; @@ -60,13 +49,32 @@ function getPlugins({ function getConfig({ external = [], + globals = {}, input = 'client/index.js' }, withScss = true) { return { input, - external: defaultExternal.concat(external), + external, + globals, plugins: getPlugins({external}, withScss), }; } -module.exports = getConfig; \ No newline at end of file +module.exports = getConfig({ + external: [ + 'underscore', + 'react', + 'react-dom', + 'react-router-dom', + 'doctrine-standalone', + 'babel-standalone' + ], + globals: { + 'underscore': '_', + 'react': 'React', + 'react-dom': 'ReactDOM', + 'react-router-dom':'ReactRouterDOM', + 'doctrine-standalone': 'doctrine', + 'babel-standalone': 'Babel' + } +}); \ No newline at end of file From b6454b7f796bd9174878cee605078c2a25215a21 Mon Sep 17 00:00:00 2001 From: Noam Elboim Date: Fri, 13 Oct 2017 11:42:22 +0300 Subject: [PATCH 12/12] chaging default rootElement to be a new element --- README.md | 4 ++-- client/index.js | 16 +++++++++------- index.html | 1 - package.json | 2 +- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 7950da0..c62b6b8 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ UiZoo.init(documentation: Object, components: Object, rootElement: HTMLElement?, **components** - Object, mapping of components name to components. See [example](https://github.com/myheritage/uizoo.js/blob/master/client/components.js). -**rootElement** - HTMLElement, will bootstrap UiZoo on that Element. Default is an element with the id 'library-_-root' +**rootElement** - HTMLElement, will bootstrap UiZoo on that Element. Default is a new element on the body. **baseRoute** Route to be the base before the UiZoo routes. Default to '/'. for example if the UiZoo is on your site like so: 'www.mysite.com/my/zoo/', the base route should be '/my/zoo/'. @@ -119,7 +119,7 @@ To add tests, use the following steps - First, make sure the app is up and running: ``` -gulp +npm start ``` The first time tests are run, install the npm dependencies: ``` diff --git a/client/index.js b/client/index.js index 4e4d2eb..cb7a55a 100644 --- a/client/index.js +++ b/client/index.js @@ -14,20 +14,22 @@ import mapComponentsByModule from './services/componentByModuleMapper'; window._extend = _.extend; // to be used instead of Object.assign -const defaultRoot = document.getElementById('library-_-root'); - /** - * Init - * @param {Object} documentation - * @param {Object} components - * @param {HTMLElement} rootElement + * Init - render UiZoo with documentation and components mappings + * @param {Object} [documentation] + * @param {Object} [components] + * @param {HTMLElement} [rootElement] will default to a new element on the body */ function init( documentation = libraryDocs, components = libraryData, - rootElement = defaultRoot, + rootElement, baseRoute = '/' ) { + if (!rootElement) { + rootElement = document.createElement('div'); + document.body.appendChild(rootElement); + } checkDependencies(documentation, components); const compiler = createCompiler(components); // JSX compiler diff --git a/index.html b/index.html index f928fcd..1a9f3e3 100644 --- a/index.html +++ b/index.html @@ -8,7 +8,6 @@ -
diff --git a/package.json b/package.json index 511bba2..2ea2e35 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "build:iife": "./node_modules/.bin/rollup -c rollup.config.js -o dist/index.js -f iife -n UiZoo", "build:cjs": "./node_modules/.bin/rollup -c rollup.config.js -o dist/index.cjs.js -f cjs -n UiZoo", "build:es": "./node_modules/.bin/rollup -c rollup.config.js -o dist/index.es.js -f es -n UiZoo", - "gulp:w": "gulp", + "gulp:w": "./node_modules/.bin/gulp", "test": "npm start & SERVER_PID=$!; (cd tests; npm i && node run-tests.js); kill $SERVER_PID" }, "main": "dist/index.cjs.js",