diff --git a/react-flux-babel-karma/README.md b/react-flux-babel-karma/README.md index bdefa0b..f7f2bf6 100644 --- a/react-flux-babel-karma/README.md +++ b/react-flux-babel-karma/README.md @@ -2,19 +2,17 @@ ## Getting started -You'll need [node / npm](https://nodejs.org/) and [Typings](https://github.com/typings/typings) installed globally. To get up and running just enter: +You'll need [node / npm](https://nodejs.org/) installed. To get up and running just enter: ``` npm install -typings install npm run serve ``` This will: -1. Download the npm packages you need -2. Download the type definitions from DefinitelyTyped that you need. -3. Compile the code and serve it up at [http://localhost:8080](http://localhost:8080) +1. Download the npm packages you need (including the type definitions from DefinitelyTyped) +2. Compile the code and serve it up at [http://localhost:8080](http://localhost:8080) Now you need dev tools. There's a world of choice out there; there's [Atom](https://atom.io/), there's [VS Code](https://www.visualstudio.com/en-us/products/code-vs.aspx), there's [Sublime](http://www.sublimetext.com/). There's even something called [Visual Studio](http://www.visualstudio.com). It's all your choice really. diff --git a/react-flux-babel-karma/gulp/webpack.js b/react-flux-babel-karma/gulp/webpack.js index 65af421..f3cff9c 100644 --- a/react-flux-babel-karma/gulp/webpack.js +++ b/react-flux-babel-karma/gulp/webpack.js @@ -3,91 +3,96 @@ var gulp = require('gulp'); var gutil = require('gulp-util'); var webpack = require('webpack'); -var failPlugin = require('webpack-fail-plugin'); var WebpackNotifierPlugin = require('webpack-notifier'); +var failPlugin = require('webpack-fail-plugin'); var webpackConfig = require('../webpack.config.js'); +var packageJson = require('../package.json'); function buildProduction(done) { - // modify some webpack config options - var myProdConfig = Object.create(webpackConfig); - myProdConfig.output.filename = '[name].[hash].js'; - - myProdConfig.plugins = myProdConfig.plugins.concat( - new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.[hash].js' }), - new webpack.optimize.DedupePlugin(), - new webpack.optimize.UglifyJsPlugin(), - failPlugin - ); - - // run webpack - webpack(myProdConfig, function(err, stats) { - if (err) { throw new gutil.PluginError('webpack:build', err); } - gutil.log('[webpack:build]', stats.toString({ - colors: true - })); - - if (done) { done(); } - }); + // modify some webpack config options + var myProdConfig = Object.create(webpackConfig); + myProdConfig.output.filename = '[name].[hash].js'; + + myProdConfig.plugins = myProdConfig.plugins.concat( + new webpack.DefinePlugin({ + 'process.env': { + 'NODE_ENV': JSON.stringify('production') + } + }), + new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.[hash].js' }), + new webpack.optimize.DedupePlugin(), + new webpack.optimize.UglifyJsPlugin(), + failPlugin + ); + + // run webpack + webpack(myProdConfig, function (err, stats) { + if (err) { throw new gutil.PluginError('webpack:build', err); } + gutil.log('[webpack:build]', stats.toString({ + colors: true + })); + + if (done) { done(); } + }); } function createDevCompiler() { - // modify some webpack config options - var myDevConfig = Object.create(webpackConfig); - myDevConfig.devtool = 'inline-source-map'; - myDevConfig.debug = true; - - myDevConfig.plugins = myDevConfig.plugins.concat( - new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.js' }), - new WebpackNotifierPlugin({ title: 'Webpack build', excludeWarnings: true }) - ); - - // create a single instance of the compiler to allow caching - return webpack(myDevConfig); + // modify some webpack config options + var myDevConfig = Object.create(webpackConfig); + myDevConfig.devtool = 'inline-source-map'; + myDevConfig.debug = true; + + myDevConfig.plugins = myDevConfig.plugins.concat( + new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.js' }), + new WebpackNotifierPlugin({ title: 'Webpack build', excludeWarnings: true }) + ); + + // create a single instance of the compiler to allow caching + return webpack(myDevConfig); } -function buildDevelopment(done, devCompiler) { - // run webpack - devCompiler.run(function(err, stats) { - if (err) { throw new gutil.PluginError('webpack:build-dev', err); } - gutil.log('[webpack:build-dev]', stats.toString({ - chunks: false, - colors: true - })); - - if (done) { done(); } - }); +function build() { + return new Promise(function (resolve, reject) { + buildProduction(function (err) { + if (err) { + reject(err); + } else { + resolve('webpack built'); + } + }); + }); } - -function bundle(options) { - var devCompiler; - - function build(done) { - if (options.shouldWatch) { - buildDevelopment(done, devCompiler); - } else { - buildProduction(done); - } - } - - if (options.shouldWatch) { - devCompiler = createDevCompiler(); - - gulp.watch('src/**/*', function() { build(); }); - } - - return new Promise(function(resolve, reject) { - build(function (err) { - if (err) { - reject(err); - } else { - resolve('webpack built'); - } - }); - }); +function watch() { + var firstBuildDone = false; + + return new Promise(function (resolve, reject) { + var devCompiler = createDevCompiler(); + devCompiler.watch({ // watch options: + aggregateTimeout: 300 // wait so long for more changes + }, function (err, stats) { + if (err) { + if (!firstBuildDone) { + firstBuildDone = true; + reject(err); + } + throw new gutil.PluginError('webpack:build-dev', err); + } else { + if (!firstBuildDone) { + firstBuildDone = true; + resolve('webpack built'); + } + } + + gutil.log('[webpack:build-dev]', stats.toString({ + chunks: false, + colors: true + })); + }); + }); } module.exports = { - build: function() { return bundle({ shouldWatch: false }); }, - watch: function() { return bundle({ shouldWatch: true }); } -}; + build: function () { return build(); }, + watch: function () { return watch(); } +}; \ No newline at end of file diff --git a/react-flux-babel-karma/karma.conf.js b/react-flux-babel-karma/karma.conf.js index 10ffba7..7257992 100644 --- a/react-flux-babel-karma/karma.conf.js +++ b/react-flux-babel-karma/karma.conf.js @@ -9,9 +9,9 @@ module.exports = function(config) { browsers: [ 'PhantomJS' ], files: [ - 'test/import-babel-polyfill.js', // This ensures we have the es6 shims in place from babel - 'test/**/*.tests.ts', - 'test/**/*.tests.tsx' + // This ensures we have the es6 shims in place from babel and that angular and angular-mocks are loaded + // and then loads all the tests + 'test/main.js' ], port: 9876, @@ -21,13 +21,11 @@ module.exports = function(config) { logLevel: config.LOG_INFO, //config.LOG_DEBUG preprocessors: { - 'test/import-babel-polyfill.js': [ 'webpack', 'sourcemap' ], - 'src/**/*.{ts,tsx}': [ 'webpack', 'sourcemap' ], - 'test/**/*.tests.{ts,tsx}': [ 'webpack', 'sourcemap' ] + 'test/main.js': [ 'webpack', 'sourcemap' ] }, webpack: { - devtool: 'eval-source-map', //'inline-source-map', + devtool: 'inline-source-map', debug: true, module: webpackConfig.module, resolve: webpackConfig.resolve diff --git a/react-flux-babel-karma/package.json b/react-flux-babel-karma/package.json index 21fd63b..99168a7 100644 --- a/react-flux-babel-karma/package.json +++ b/react-flux-babel-karma/package.json @@ -16,7 +16,7 @@ "keywords": [ "React", "Flux", - "ES6", + "ES2016", "typescript" ], "author": "John Reilly", @@ -26,16 +26,22 @@ }, "homepage": "https://github.com/Microsoft/TypeScriptSamples/tree/master/es6-babel-react-flux-karma#readme", "devDependencies": { + "@types/fbemitter": "^2.0.32", + "@types/flux": "0.0.32", + "@types/jasmine": "^2.5.35", + "@types/react": "^0.14.41", + "@types/react-addons-test-utils": "^0.14.15", + "@types/react-bootstrap": "0.0.33", + "@types/react-dom": "^0.14.18", "babel": "^6.0.0", "babel-core": "^6.0.0", "babel-loader": "^6.0.0", - "babel-polyfill": "^6.0.0", "babel-preset-es2015": "^6.0.0", + "babel-preset-es2016": "^6.16.0", "babel-preset-react": "^6.0.0", "del": "^2.0.2", "eslint": "^2.0.0", "express": "^4.13.3", - "flux": "^2.0.3", "glob": "^7.0.0", "gulp": "^3.9.0", "gulp-autoprefixer": "^3.1.0", @@ -50,23 +56,28 @@ "gulp-uglify": "^1.2.0", "gulp-util": "^3.0.6", "jasmine-core": "^2.3.4", - "karma": "^0.13.10", - "karma-coverage": "^0.5.2", - "karma-jasmine": "^0.3.6", - "karma-junit-reporter": "^0.3.7", + "karma": "^1.2.0", + "karma-coverage": "^1.0.0", + "karma-jasmine": "^1.0.0", + "karma-junit-reporter": "^1.0.0", "karma-mocha-reporter": "^2.0.0", - "karma-notify-reporter": "^0.1.1", + "karma-notify-reporter": "^1.0.0", "karma-phantomjs-launcher": "^1.0.0", "karma-sourcemap-loader": "^0.3.6", "karma-webpack": "^1.7.0", "phantomjs-prebuilt": "^2.1.4", - "react": "^0.14.3", - "react-addons-test-utils": "^0.14.3", - "react-dom": "^0.14.3", - "ts-loader": "^0.8.1", - "typescript": "^1.8.0", + "ts-loader": "^1.3.1", + "typescript": "^2.1.4", "webpack": "^1.12.2", "webpack-fail-plugin": "^1.0.4", "webpack-notifier": "^1.2.1" + }, + "dependencies": { + "babel-polyfill": "^6.0.0", + "flux": "^2.0.3", + "fbemitter": "^2.0.2", + "react": "^15.4.1", + "react-addons-test-utils": "^15.4.1", + "react-dom": "^15.4.1" } } diff --git a/react-flux-babel-karma/src/components/App.tsx b/react-flux-babel-karma/src/components/App.tsx index e43face..99cbd30 100644 --- a/react-flux-babel-karma/src/components/App.tsx +++ b/react-flux-babel-karma/src/components/App.tsx @@ -1,11 +1,13 @@ -import * as React from 'react'; +import React from 'react'; +import FBEmitter from "fbemitter"; + import GreetingStore from '../stores/GreetingStore'; -import * as GreetingActions from '../actions/GreetingActions'; import GreetingState from '../types/GreetingState'; import WhoToGreet from './WhoToGreet'; import Greeting from './Greeting'; class App extends React.Component<{}, GreetingState> { + eventSubscription: FBEmitter.EventSubscription; constructor(props: {}) { super(props); this.state = this.getStateFromStores(); @@ -15,11 +17,11 @@ class App extends React.Component<{}, GreetingState> { } public componentWillMount() { - GreetingStore.addChangeListener(this.onChange); + this.eventSubscription = GreetingStore.addChangeListener(this.onChange); } public componentWillUnmount() { - GreetingStore.removeChangeListener(this.onChange); + this.eventSubscription.remove(); } render() { diff --git a/react-flux-babel-karma/src/components/Greeting.tsx b/react-flux-babel-karma/src/components/Greeting.tsx index 7d1502b..0305fdb 100644 --- a/react-flux-babel-karma/src/components/Greeting.tsx +++ b/react-flux-babel-karma/src/components/Greeting.tsx @@ -1,4 +1,5 @@ -import * as React from 'react'; +import React from 'react'; + import * as GreetingActions from '../actions/GreetingActions'; interface Props { @@ -28,7 +29,7 @@ class Greeting extends React.Component { ); } - _onClick = (event: React.MouseEvent) => { + _onClick = (_event: React.MouseEvent) => { GreetingActions.removeGreeting(this.props.targetOfGreeting); } } diff --git a/react-flux-babel-karma/src/components/WhoToGreet.tsx b/react-flux-babel-karma/src/components/WhoToGreet.tsx index 6712746..eac78fe 100644 --- a/react-flux-babel-karma/src/components/WhoToGreet.tsx +++ b/react-flux-babel-karma/src/components/WhoToGreet.tsx @@ -1,4 +1,5 @@ -import * as React from 'react'; +import React from 'react'; + import * as GreetingActions from '../actions/GreetingActions'; interface Props { @@ -35,12 +36,12 @@ class WhoToGreet extends React.Component { return !this.props.newGreeting; } - _handleNewGreetingChange = (event: React.FormEvent) => { + _handleNewGreetingChange = (event: React.FormEvent) => { const newGreeting = (event.target as HTMLInputElement).value; GreetingActions.newGreetingChanged(newGreeting); } - _onSubmit = (event: React.FormEvent) => { + _onSubmit = (event: React.FormEvent) => { event.preventDefault(); if (!this._preventSubmission) { diff --git a/react-flux-babel-karma/src/dispatcher/AppDispatcher.ts b/react-flux-babel-karma/src/dispatcher/AppDispatcher.ts index 83f413c..be9360f 100644 --- a/react-flux-babel-karma/src/dispatcher/AppDispatcher.ts +++ b/react-flux-babel-karma/src/dispatcher/AppDispatcher.ts @@ -6,6 +6,6 @@ export class TypedEvent

{ export type Event = TypedEvent; -const dispatcherInstance: Flux.Dispatcher = new Dispatcher(); +const dispatcherInstance: Dispatcher = new Dispatcher(); export { dispatcherInstance as AppDispatcher }; diff --git a/react-flux-babel-karma/src/main.tsx b/react-flux-babel-karma/src/main.tsx index 1e14a73..65b3f94 100644 --- a/react-flux-babel-karma/src/main.tsx +++ b/react-flux-babel-karma/src/main.tsx @@ -1,6 +1,7 @@ import 'babel-polyfill'; -import * as React from 'react'; -import * as ReactDOM from 'react-dom'; +import React from 'react'; +import ReactDOM from 'react-dom'; + import App from './components/App'; ReactDOM.render(, document.getElementById('content')); diff --git a/react-flux-babel-karma/src/stores/FluxStore.ts b/react-flux-babel-karma/src/stores/FluxStore.ts index 4ef8407..758ec6c 100644 --- a/react-flux-babel-karma/src/stores/FluxStore.ts +++ b/react-flux-babel-karma/src/stores/FluxStore.ts @@ -1,4 +1,4 @@ -import { EventEmitter } from 'events'; +import { EventEmitter } from 'fbemitter'; import { Event } from '../dispatcher/AppDispatcher'; import * as Flux from "flux"; @@ -34,14 +34,10 @@ class FluxStore { hasChanged() { return this.changed; } addChangeListener(callback: () => void) { - this.emitter.on(CHANGE_EVENT, callback); + return this.emitter.addListener(CHANGE_EVENT, callback); } - removeChangeListener(callback: () => void) { - this.emitter.removeListener(CHANGE_EVENT, callback); - } - - protected cleanState() { + public cleanState() { this.changed = false; this.state = this.cleanStateFn(); } diff --git a/react-flux-babel-karma/src/stores/GreetingStore.ts b/react-flux-babel-karma/src/stores/GreetingStore.ts index 30b3251..9ea01b4 100644 --- a/react-flux-babel-karma/src/stores/GreetingStore.ts +++ b/react-flux-babel-karma/src/stores/GreetingStore.ts @@ -4,7 +4,7 @@ import GreetingState from '../types/GreetingState'; import { AddGreetingEvent, RemoveGreeting, NewGreetingChanged } from '../actions/GreetingActions'; class GreeterStore extends FluxStore { - constructor(dispatcher: Flux.Dispatcher) { + constructor(dispatcher: typeof AppDispatcher) { const onDispatch = (action: Event) => { if (action instanceof AddGreetingEvent) { const {payload} = action; diff --git a/react-flux-babel-karma/src/tsconfig.json b/react-flux-babel-karma/src/tsconfig.json deleted file mode 100644 index 2ec4842..0000000 --- a/react-flux-babel-karma/src/tsconfig.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "compileOnSave": false, - "filesGlob": [ - "../typings/globals/**/*.*.ts", - "!../typings/globals/jasmine/index.d.ts", - "!../typings/globals/react-addons-test-utils/index.d.ts", - "**/*.{ts,tsx}" - ], - "compilerOptions": { - "jsx": "preserve", - "target": "es6", - "noImplicitAny": true, - "removeComments": false, - "preserveConstEnums": true, - "sourceMap": true - }, - "files": [ - "../typings/globals/react/index.d.ts", - "../typings/globals/react-dom/index.d.ts", - "../typings/globals/flux/index.d.ts", - "../typings/globals/node/index.d.ts", - "actions/GreetingActions.ts", - "components/App.tsx", - "components/Greeting.tsx", - "components/WhoToGreet.tsx", - "dispatcher/AppDispatcher.ts", - "main.tsx", - "stores/FluxStore.ts", - "stores/GreetingStore.ts", - "types/GreetingState.ts" - ], - "atom": { - "rewriteTsconfig": true - } -} diff --git a/react-flux-babel-karma/test/components/App.tests.tsx b/react-flux-babel-karma/test/components/App.tests.tsx index 42b1bf9..468b7da 100644 --- a/react-flux-babel-karma/test/components/App.tests.tsx +++ b/react-flux-babel-karma/test/components/App.tests.tsx @@ -1,5 +1,6 @@ -import * as React from 'react'; -import * as TestUtils from 'react-addons-test-utils'; +import React from 'react'; +import TestUtils from 'react-addons-test-utils'; + import App from '../../src/components/App'; import WhoToGreet from '../../src/components/WhoToGreet'; import Greeting from '../../src/components/Greeting'; diff --git a/react-flux-babel-karma/test/components/Greeting.tests.tsx b/react-flux-babel-karma/test/components/Greeting.tests.tsx index 9ea44b4..18a8724 100644 --- a/react-flux-babel-karma/test/components/Greeting.tests.tsx +++ b/react-flux-babel-karma/test/components/Greeting.tests.tsx @@ -1,5 +1,6 @@ -import * as React from 'react'; -import * as TestUtils from 'react-addons-test-utils'; +import React from 'react'; +import TestUtils from 'react-addons-test-utils'; + import Greeting from '../../src/components/Greeting'; import * as GreetingActions from '../../src/actions/GreetingActions'; @@ -36,7 +37,7 @@ describe('Greeting', () => { expect(GreetingActions.removeGreeting).toHaveBeenCalledWith(targetOfGreeting); }); - function render({ targetOfGreeting }) { + function render({ targetOfGreeting }: { targetOfGreeting: string; }) { const shallowRenderer = TestUtils.createRenderer(); shallowRenderer.render(); return shallowRenderer.getRenderOutput(); diff --git a/react-flux-babel-karma/test/components/WhoToGreet.tests.tsx b/react-flux-babel-karma/test/components/WhoToGreet.tests.tsx index e514ec3..47ecdd4 100644 --- a/react-flux-babel-karma/test/components/WhoToGreet.tests.tsx +++ b/react-flux-babel-karma/test/components/WhoToGreet.tests.tsx @@ -1,5 +1,6 @@ -import * as React from 'react'; -import * as TestUtils from 'react-addons-test-utils'; +import React from 'react'; +import TestUtils from 'react-addons-test-utils'; + import WhoToGreet from '../../src/components/WhoToGreet'; import * as GreetingActions from '../../src/actions/GreetingActions'; @@ -59,7 +60,7 @@ describe('WhoToGreet', () => { expect(GreetingActions.addGreeting).toHaveBeenCalledWith(newGreeting); }); - function render({ newGreeting }) { + function render({ newGreeting }: { newGreeting: string }) { const shallowRenderer = TestUtils.createRenderer(); shallowRenderer.render(); return shallowRenderer.getRenderOutput(); diff --git a/react-flux-babel-karma/test/import-babel-polyfill.js b/react-flux-babel-karma/test/import-babel-polyfill.js deleted file mode 100644 index b012711..0000000 --- a/react-flux-babel-karma/test/import-babel-polyfill.js +++ /dev/null @@ -1 +0,0 @@ -import 'babel-polyfill'; diff --git a/react-flux-babel-karma/test/main.js b/react-flux-babel-karma/test/main.js new file mode 100644 index 0000000..1b332a7 --- /dev/null +++ b/react-flux-babel-karma/test/main.js @@ -0,0 +1,5 @@ +/* eslint-disable */ +import 'babel-polyfill'; + +const testsContext = require.context('./', true, /\.tests\.ts(x?)$/); +testsContext.keys().forEach(testsContext); \ No newline at end of file diff --git a/react-flux-babel-karma/test/tsconfig.json b/react-flux-babel-karma/test/tsconfig.json deleted file mode 100644 index 8ab80b6..0000000 --- a/react-flux-babel-karma/test/tsconfig.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "compileOnSave": false, - "filesGlob": [ - "**/*.{ts,tsx}", - "../typings/globals/**/*.*.ts" - ], - "compilerOptions": { - "jsx": "preserve", - "target": "es6", - "module": "commonjs", - "noImplicitAny": true, - "preserveConstEnums": true, - "sourceMap": true - }, - "files": [ - "../typings/globals/react/index.d.ts", - "../typings/globals/react-dom/index.d.ts", - "../typings/globals/react-addons-test-utils/index.d.ts", - "../typings/globals/flux/index.d.ts", - "../typings/globals/jasmine/index.d.ts", - "../typings/globals/node/index.d.ts", - "components/App.tests.tsx", - "components/Greeting.tests.tsx", - "components/WhoToGreet.tests.tsx", - "stores/GreetingStore.tests.ts" - ], - "atom": { - "rewriteTsconfig": true - } -} diff --git a/react-flux-babel-karma/tsconfig.json b/react-flux-babel-karma/tsconfig.json new file mode 100644 index 0000000..cb31633 --- /dev/null +++ b/react-flux-babel-karma/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "lib": [ + "dom", + "es2015", + "es2016" + ], + "jsx": "preserve", + "target": "es2016", + "module": "es2015", + "moduleResolution": "node", + "noImplicitAny": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "removeComments": false, + "preserveConstEnums": true, + "sourceMap": true, + "skipLibCheck": true + } +} \ No newline at end of file diff --git a/react-flux-babel-karma/typings.json b/react-flux-babel-karma/typings.json deleted file mode 100644 index 9cd2b81..0000000 --- a/react-flux-babel-karma/typings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "es6-babel-react-flux-karma", - "version": false, - "globalDependencies": { - "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#bcd5761826eb567876c197ccc6a87c4d05731054", - "flux": "github:DefinitelyTyped/DefinitelyTyped/flux/flux.d.ts#bcd5761826eb567876c197ccc6a87c4d05731054", - "node": "github:DefinitelyTyped/DefinitelyTyped/node/node.d.ts#bcd5761826eb567876c197ccc6a87c4d05731054", - "react": "github:DefinitelyTyped/DefinitelyTyped/react/react.d.ts#bcd5761826eb567876c197ccc6a87c4d05731054", - "react-dom": "github:DefinitelyTyped/DefinitelyTyped/react/react-dom.d.ts#bcd5761826eb567876c197ccc6a87c4d05731054", - "react-addons-test-utils": "github:DefinitelyTyped/DefinitelyTyped/react/react-addons-test-utils.d.ts#bcd5761826eb567876c197ccc6a87c4d05731054" - } -}