diff --git a/.circleci/config.yml b/.circleci/config.yml index 661580a..af5d6e3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -37,7 +37,7 @@ jobs: - run: name: Build react-tv - command: yarn build:prod + command: yarn build - run: name: Build status react-tv diff --git a/CHANGELOG.md b/CHANGELOG.md index b00348c..9cd2ca3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# 0.4.0 + +- react `^16.3.2` +- react-reconciler `0.10.0` +- support to React DevTools +- fixes on development bundle +- `development` and `production` bundles based on `process.node.env` + # 0.3.4 - update `react-tv-navigation` on react-tv-cli generator to 0.4.0 diff --git a/README.md b/README.md index f585298..93894a6 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,10 @@ const Component = () => (
) const App = renderOnAppLoaded(Component) ``` +### `findDOMNode` + +Similar to [react-dom findDOMNode](https://reactjs.org/docs/react-dom.html#finddomnode) + ### Navigation If you want to start with Navigation for TVs. React-TV provides a package for spatial navigation with declarative support based on [Netflix navigation system](https://medium.com/netflix-techblog/pass-the-remote-user-input-on-tv-devices-923f6920c9a8). diff --git a/package.json b/package.json index ada8d8e..14ba8ac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "0.3.4", + "version": "0.4.0", "workspaces": [ "packages/*", "examples/*" @@ -9,14 +9,14 @@ "postinstall": "yarn build", "lint": "node ./scripts/eslint/index.js", "linc": "node ./scripts/eslint/only-changed.js", + "benchmark-memory": "node scripts/benchmark/memory.js", "build": "node scripts/rollup/build.js", - "build:prod": "cross-env NODE_ENV=PROD node scripts/rollup/build.js", "build:stats": "node scripts/rollup/stats.js", - "prepublishOnly": "yarn test && yarn build:prod", + "prepublishOnly": "yarn test && yarn build", "prettier:stat": "node ./scripts/prettier/index.js", "clean-node-modules": "find ./ -name 'node_modules' -exec rm -rf '{}' +", "test": "yarn lint && yarn prettier:stat && yarn flow && yarn jest:ci", - "jest": "cross-env NODE_ENV=TEST jest --testPathIgnorePatterns \"(__fixtures__|matcher.js)\"", + "jest": "cross-env NODE_ENV=TEST jest --no-cache --testPathIgnorePatterns \"(__fixtures__|matcher.js)\"", "jest:ci": "cross-env NODE_ENV=TEST jest --no-cache --testPathIgnorePatterns \"(__fixtures__|matcher.js)\" --ci --runInBand", "flow": "flow", "prettier": "node ./scripts/prettier/index.js write-changed", @@ -24,7 +24,7 @@ }, "devDependencies": { "babel-eslint": "^7.1.0", - "babel-jest": "20.1.0-delta.1", + "babel-jest": "21.0.2", "babel-plugin-external-helpers": "^6.22.0", "babel-plugin-transform-flow-strip-types": "^6.22.0", "babel-plugin-transform-runtime": "^6.23.0", @@ -42,11 +42,15 @@ "eslint-plugin-react": "^6.7.1", "fbjs": "^0.8.4", "flow-bin": "^0.63.1", - "jest": "20.1.0-delta.1", + "glob": "^7.1.2", + "jest": "21.0.2", + "memory-inspector": "^0.0.4", + "minimatch": "^3.0.4", "prettier": "^1.5.3", - "react": "^16.2.0", + "react": "^16.3.2", + "react-dom": "^16.3.2", "react-fiber-types": "file:./packages/react-tv/renderer/types", - "react-reconciler": "^0.7.0", + "react-reconciler": "^0.10.0", "react-test-renderer": "^16.2.0", "rimraf": "^2.6.2", "rollup": "^0.52.0", diff --git a/packages/react-tv-cli/bootstrap/custom-app/package.json b/packages/react-tv-cli/bootstrap/custom-app/package.json index e218db8..1448790 100644 --- a/packages/react-tv-cli/bootstrap/custom-app/package.json +++ b/packages/react-tv-cli/bootstrap/custom-app/package.json @@ -24,8 +24,8 @@ "babel-preset-react": "^6.24.1", "cross-env": "^5.1.1", "react": "^16.2.0", - "react-tv": "^0.3.4", - "react-tv-cli": "^0.3.4", + "react-tv": "^0.4.0", + "react-tv-cli": "^0.4.0", "react-tv-navigation": "^0.4.0", "webpack": "^3.8.1", "webpack-dev-server": "^2.9.4" diff --git a/packages/react-tv-cli/package.json b/packages/react-tv-cli/package.json index a01c833..cc1509a 100644 --- a/packages/react-tv-cli/package.json +++ b/packages/react-tv-cli/package.json @@ -1,6 +1,6 @@ { "name": "react-tv-cli", - "version": "0.3.4", + "version": "0.4.0", "description": "Packager for TVs", "bin": { "react-tv-cli": "index.js" diff --git a/packages/react-tv/ReactTVEntry.js b/packages/react-tv/ReactTVEntry.js index 08691b9..8ea6061 100644 --- a/packages/react-tv/ReactTVEntry.js +++ b/packages/react-tv/ReactTVEntry.js @@ -8,15 +8,13 @@ */ import ReactTVRenderer from './renderer/ReactTVFiberEntry'; -import Platform from './modules/Platform'; -import renderOnAppLoaded from './modules/renderOnAppLoaded'; +import PlatformModule from './modules/Platform'; +import renderOnAppLoadedModule from './modules/renderOnAppLoaded'; -const ReactTV = { - render: ReactTVRenderer.render, - findDOMNode: ReactTVRenderer.findDOMNode, - unmountComponentAtNode: ReactTVRenderer.unmountComponentAtNode, - renderOnAppLoaded: renderOnAppLoaded, - Platform: Platform, -}; +export const render = ReactTVRenderer.render; +export const findDOMNode = ReactTVRenderer.findDOMNode; +export const unmountComponentAtNode = ReactTVRenderer.unmountComponentAtNode; +export const renderOnAppLoaded = renderOnAppLoadedModule; +export const Platform = PlatformModule; -module.exports = ReactTV.default ? ReactTV.default : ReactTV; +export default ReactTVRenderer; diff --git a/packages/react-tv/__tests__/ReactTVEntry-test.js b/packages/react-tv/__tests__/ReactTVEntry-test.js index 978450e..109fb84 100644 --- a/packages/react-tv/__tests__/ReactTVEntry-test.js +++ b/packages/react-tv/__tests__/ReactTVEntry-test.js @@ -1,12 +1,12 @@ import React from 'react'; -import ReactTV from '../ReactTVEntry.js'; +import ReactTV, {Platform} from '../ReactTVEntry.js'; describe('[render] Integration between renderer and modules', () => { it('should renderer to expected Element', () => { const root = document.createElement('div'); function MyComponent() { let currentPlatform = 'LG WebOS'; - if (!ReactTV.Platform('webos')) { + if (!Platform('webos')) { currentPlatform = 'Browser'; } diff --git a/packages/react-tv/index.js b/packages/react-tv/index.js new file mode 100644 index 0000000..680687e --- /dev/null +++ b/packages/react-tv/index.js @@ -0,0 +1,5 @@ +if (process.env.NODE_ENV === 'production') { + module.exports = require('./dist/react-tv.production.js'); +} else { + module.exports = require('./dist/react-tv.development.js'); +} diff --git a/packages/react-tv/package.json b/packages/react-tv/package.json index 8a626fd..623b0a6 100644 --- a/packages/react-tv/package.json +++ b/packages/react-tv/package.json @@ -1,10 +1,11 @@ { "name": "react-tv", - "version": "0.3.4", + "version": "0.4.0", "description": "React renderer for low memory applications", - "main": "dist/react-tv.umd.js", + "main": "index.js", "files": [ - "dist/" + "dist/", + "index.js" ], "repository": { "type": "git", diff --git a/packages/react-tv/renderer/ReactTVFiberEntry.js b/packages/react-tv/renderer/ReactTVFiberEntry.js index e80016a..8adc24f 100644 --- a/packages/react-tv/renderer/ReactTVFiberEntry.js +++ b/packages/react-tv/renderer/ReactTVFiberEntry.js @@ -43,13 +43,6 @@ const { const {precacheFiberNode, updateFiberProps} = ReactDOMComponentTree; -const LOG_STEPS = false; -const log = (a, b, c) => { - if (LOG_STEPS) { - console.log(a, b, c); - } -}; - const ReactTVFiberRenderer = ReactFiberReconciler({ createInstance( type: string, @@ -58,8 +51,6 @@ const ReactTVFiberRenderer = ReactFiberReconciler({ hostContext: HostContext, internalInstanceHandle: Object ): Object { - log('createInstance'); - let parentNamespace: string; parentNamespace = hostContext; @@ -79,7 +70,6 @@ const ReactTVFiberRenderer = ReactFiberReconciler({ parentInstance: Instance, child: Instance | TextInstance ): void { - log('appendInitialChild', parentInstance, child); parentInstance.appendChild(child); }, @@ -89,7 +79,6 @@ const ReactTVFiberRenderer = ReactFiberReconciler({ props: Props, rootContainerInstance: Container ): boolean { - log('finalizeInitialChildren', domElement); setInitialProperties(domElement, type, props, rootContainerInstance); }, @@ -101,7 +90,6 @@ const ReactTVFiberRenderer = ReactFiberReconciler({ rootContainerInstance: Container, hostContext: HostContext ): null | ArraySure!
; + return(this.input = node)}>Sure!
; } } diff --git a/packages/react-tv/renderer/shared/DOMNamespaces.js b/packages/react-tv/renderer/shared/DOMNamespaces.js index 54d5e2b..fede898 100644 --- a/packages/react-tv/renderer/shared/DOMNamespaces.js +++ b/packages/react-tv/renderer/shared/DOMNamespaces.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2017-present, Raphael. + * Copyright (c) 2017-present, Raphael Amorim. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. @@ -11,14 +11,14 @@ const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml'; const MATH_NAMESPACE = 'http://www.w3.org/1998/Math/MathML'; const SVG_NAMESPACE = 'http://www.w3.org/2000/svg'; -const Namespaces = { +export const Namespaces = { html: HTML_NAMESPACE, mathml: MATH_NAMESPACE, svg: SVG_NAMESPACE, }; // Assumes there is no parent namespace. -function getIntrinsicNamespace(type: string): string { +export function getIntrinsicNamespace(type: string): string { switch (type) { case 'svg': return SVG_NAMESPACE; @@ -29,7 +29,7 @@ function getIntrinsicNamespace(type: string): string { } } -function getChildNamespace( +export function getChildNamespace( parentNamespace: string | null, type: string ): string { @@ -44,7 +44,3 @@ function getChildNamespace( // By default, pass namespace below. return parentNamespace; } - -exports.Namespaces = Namespaces; -exports.getIntrinsicNamespace = getIntrinsicNamespace; -exports.getChildNamespace = getChildNamespace; diff --git a/packages/react-tv/renderer/shared/utils/isCustomComponent.js b/packages/react-tv/renderer/shared/utils/isCustomComponent.js index 873dcb8..50bb921 100644 --- a/packages/react-tv/renderer/shared/utils/isCustomComponent.js +++ b/packages/react-tv/renderer/shared/utils/isCustomComponent.js @@ -31,4 +31,4 @@ function isCustomComponent(tagName: string, props: Object) { } } -module.exports = isCustomComponent; +export default isCustomComponent; diff --git a/scripts/benchmark/memory.js b/scripts/benchmark/memory.js new file mode 100644 index 0000000..4d77efb --- /dev/null +++ b/scripts/benchmark/memory.js @@ -0,0 +1,70 @@ +/*global React, ReactTV, ReactDOM*/ + +const inspect = require('./../../../memory-inspector'); + +const ReactPath = + '/Users/hamorim/Documents/life/react-tv/node_modules/react/umd/react.production.min.js'; +const ReactTVPath = + '/Users/hamorim/Documents/life/react-tv/packages/react-tv/dist/react-tv.production.js'; +const ReactDOMPath = + '/Users/hamorim/Documents/life/react-tv/node_modules/react-dom/umd/react-dom.production.min.js'; + +const renderApp = renderMethod => () => { + class Clock extends React.Component { + constructor() { + super(); + this.state = {date: new Date()}; + } + + componentDidMount() { + setInterval(() => this.setState({date: new Date()}), 1000); + } + + render() { + return React.createElement( + 'div', + {class: 'container'}, + React.createElement('img', {src: 'https://i.imgur.com/9yhDR0Q.png'}), + React.createElement( + 'h1', + null, + 'You ', + this.state.date.toLocaleTimeString() + ), + React.createElement('p', null, 'In Browser') + ); + } + } + + let render; + if (window && window.ReactTV) { + render = ReactTV.render; + console.log('using react-tv'); + } else { + render = ReactDOM.render; + console.log('using react-dom'); + } + + render(React.createElement(Clock, null), document.getElementById('root')); +}; + +// Should not pass 5MB +inspect({ + evaluate: renderApp, + scripts: [ReactPath, ReactTVPath], + delay: 1000, + maxMemoryLimit: 5 * 1048576, + maxMemoryPercentThreshold: 90, +}).then(memoryReportTV => { + console.log(memoryReportTV); + + inspect({ + evaluate: renderApp, + scripts: [ReactPath, ReactDOMPath], + delay: 3000, + maxMemoryLimit: 5 * 1048576, + maxMemoryPercentThreshold: 90, + }).then(memoryReportDOM => { + console.log(memoryReportDOM); + }); +}); diff --git a/scripts/rollup/build.js b/scripts/rollup/build.js index b2645a0..216cd54 100644 --- a/scripts/rollup/build.js +++ b/scripts/rollup/build.js @@ -14,10 +14,10 @@ const packagePath = 'packages/react-tv'; let tasks = []; -function stripEnvVariables(production) { +function stripEnvVariables(env) { return { - __DEV__: production ? 'false' : 'true', - 'process.env.NODE_ENV': production ? "'production'" : "'development'", + __DEV__: env === 'production' ? 'false' : 'true', + 'process.env.NODE_ENV': "'" + env + "'", }; } @@ -29,12 +29,14 @@ function createBundle({entryPath, bundleType, destName}) { let plugins = [ flow(), - replace(stripEnvVariables()), + replace(stripEnvVariables(bundleType)), babel({ exclude: 'node_modules/**', externalHelpers: false, }), - commonjs(), + commonjs({ + include: 'node_modules/**', + }), resolve({ jsnext: true, main: true, @@ -42,7 +44,7 @@ function createBundle({entryPath, bundleType, destName}) { }), ]; - if (bundleType.indexOf('PROD') >= 0) { + if (bundleType.indexOf('production') >= 0) { plugins = plugins.concat([optimizeJs(), uglify()]); } @@ -53,7 +55,7 @@ function createBundle({entryPath, bundleType, destName}) { }).then(bundle => { tasks.push( bundle.write({ - format: bundleType === 'PROD-UMD' ? 'umd' : 'iife', + format: 'umd', name: 'ReactTV', file: `${packagePath}/dist/${destName}`, }) @@ -61,31 +63,17 @@ function createBundle({entryPath, bundleType, destName}) { }); } -if (process.env.NODE_ENV === 'PROD') { - createBundle({ - entryPath: `${packagePath}/ReactTVEntry.js`, - bundleType: 'PROD', - destName: 'react-tv.min.js', - }); - - createBundle({ - entryPath: `${packagePath}/ReactTVEntry.js`, - bundleType: 'PROD-UMD', - destName: 'react-tv.umd.js', - }); -} else { - createBundle({ - entryPath: `${packagePath}/ReactTVEntry.js`, - bundleType: 'PROD-UMD', - destName: 'react-tv.umd.js', - }); +createBundle({ + entryPath: `${packagePath}/ReactTVEntry.js`, + bundleType: 'production', + destName: 'react-tv.production.js', +}); - // createBundle({ - // entryPath: `${packagePath}/ReactTVEntry.js`, - // bundleType: 'DEV', - // destName: 'react-tv.js', - // }); -} +createBundle({ + entryPath: `${packagePath}/ReactTVEntry.js`, + bundleType: 'development', + destName: 'react-tv.development.js', +}); Promise.all(tasks).catch(error => { Promise.reject(error); diff --git a/scripts/rollup/stats.js b/scripts/rollup/stats.js index 5a177af..6a0bb17 100644 --- a/scripts/rollup/stats.js +++ b/scripts/rollup/stats.js @@ -2,7 +2,7 @@ const fs = require('fs'); const path = require('path'); const Table = require('cli-table'); -const files = ['react-tv.umd.js', 'react-tv.min.js']; +const files = ['react-tv.development.js', 'react-tv.production.js']; const sizeInfo = ['size']; const table = new Table({