Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add build process to all addons #9946

Merged
merged 5 commits into from
Jun 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions addons/create-react-class/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ var factory = require('./factory');

if (typeof React === 'undefined') {
throw Error(
'createReactClass could not find the React object. If you are using script tags, ' +
'make sure that React is being loaded before createReactClass.'
'create-react-class could not find the React object. If you are using script tags, ' +
'make sure that React is being loaded before create-react-class.'
);
}

Expand Down
73 changes: 73 additions & 0 deletions addons/postbuild.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* Copyright 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @emails react-core
*/

'use strict';

var fs = require('fs');
var path = require('path');

// This lets us import Webpack config without crashing
process.env.NODE_ENV = 'development';

// This script runs from the addon folder
var exportName = require(path.resolve(process.cwd(), './webpack.config')).output
.library;
var packageName = path.basename(process.cwd());

if (packageName.indexOf('react-addons') !== 0) {
throw new Error(
'Only run this script for packages that used to be published as addons.'
);
}

// Inputs
// DEV: root["exportName"] = factory(root["React"])
// PROD: e.exportName=t(e.React)
var find = new RegExp(
'((?!exports)\\b\\w+)(\\["' +
exportName +
'"\\]|\\.' +
exportName +
')\\s*=\\s*(\\w+)\\((.*)\\)'
);
// Outputs
// DEV: (root.React ? (root.React.addons = root.React.addons || {}) : /* throw */).exportName = factory(/* ... */);
// PROD: (e.React ? (e.React.addons = e.React.addons || {}) : /* throw */).exportName = t(/* ... */)
var throwIIFE = [
'(function(){',
'throw new Error("' +
packageName +
' could not find the React object. If you are using script tags, make sure that React is being loaded before ' +
packageName +
'.")',
'})()',
].join('');
var replace =
'($1.React?($1.React.addons=$1.React.addons||{}):' +
throwIIFE +
').' +
exportName +
'=$3($4)';

console.log('Tweaking the development UMD...');
var devUMD = fs.readFileSync('./' + packageName + '.js', 'utf8').toString();
devUMD = devUMD.replace(find, replace);
fs.writeFileSync('./' + packageName + '.js', devUMD);

console.log('Tweaking the production UMD...');
var prodUMD = fs
.readFileSync('./' + packageName + '.min.js', 'utf8')
.toString();
prodUMD = prodUMD.replace(find, replace);
fs.writeFileSync('./' + packageName + '.min.js', prodUMD);

console.log('Done.');
console.log('Note that you need to manually test the UMD builds.');
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We test UMDs, but then this script overrides them to tack things onto React.addons object.

It would be nice to make this more solid but I'm a bit out of ideas or care here. I'll test that it works manually later and I'd just leave it at that. It's still better than lack of any tests..

2 changes: 2 additions & 0 deletions addons/react-addons-create-fragment/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
react-addons-create-fragment.js
react-addons-create-fragment.min.js
7 changes: 5 additions & 2 deletions addons/react-addons-create-fragment/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@
"react-addons-create-fragment.min.js"
],
"scripts": {
"test": "jest",
"prepublish": "npm test"
"test": "TEST_ENTRY=./index.js jest",
"build:dev": "NODE_ENV=development webpack && TEST_ENTRY=./react-addons-create-fragment.js jest",
"build:prod": "NODE_ENV=production webpack && NODE_ENV=production TEST_ENTRY=./react-addons-create-fragment.min.js jest",
"build": "npm run build:dev && npm run build:prod && node ../postbuild.js",
"prepublish": "npm test && npm run build"
},
"devDependencies": {
"jest": "^19.0.2",
Expand Down
76 changes: 61 additions & 15 deletions addons/react-addons-create-fragment/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,78 @@
var React;
var createReactFragment;

// For testing DOM Fiber.
global.requestAnimationFrame = function(callback) {
setTimeout(callback);
// Catch stray warnings
var env = jasmine.getEnv();
var callCount = 0;
var oldError = console.error;
var newError = function() {
callCount++;
oldError.apply(this, arguments);
};

global.requestIdleCallback = function(callback) {
setTimeout(() => {
callback({
timeRemaining() {
return Infinity;
},
});
console.error = newError;
env.beforeEach(() => {
callCount = 0;
jasmine.addMatchers({
toBeReset() {
return {
compare(actual) {
if (actual !== newError && !jasmine.isSpy(actual)) {
return {
pass: false,
message: 'Test did not tear down console.error mock properly.',
};
}
return {pass: true};
},
};
},
toNotHaveBeenCalled() {
return {
compare(actual) {
return {
pass: callCount === 0,
message: 'Expected test not to warn. If the warning is expected, mock ' +
"it out using spyOn(console, 'error'); and test that the " +
'warning occurs.',
};
},
};
},
});
};
});
env.afterEach(() => {
expect(console.error).toBeReset();
expect(console.error).toNotHaveBeenCalled();
});

const expectDev = function expectDev(actual) {
// Suppress warning expectations for prod builds
function suppressDevMatcher(obj, name) {
const original = obj[name];
obj[name] = function devMatcher() {
try {
original.apply(this, arguments);
} catch (e) {
// skip
}
};
}
function expectDev(actual) {
const expectation = expect(actual);
if (process.env.NODE_ENV === 'production') {
Object.keys(expectation).forEach(name => {
suppressDevMatcher(expectation, name);
suppressDevMatcher(expectation.not, name);
});
}
return expectation;
};
}

describe('createReactFragment', () => {
beforeEach(() => {
jest.resetModules();

React = require('react');
createReactFragment = require('./index');
createReactFragment = require(process.env.TEST_ENTRY);
});

it('warns for numeric keys on objects as children', () => {
Expand Down
63 changes: 63 additions & 0 deletions addons/react-addons-create-fragment/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @emails react-core
*/

'use strict';

const webpack = require('webpack');

let __DEV__;
switch (process.env.NODE_ENV) {
case 'development':
__DEV__ = true;
break;
case 'production':
__DEV__ = false;
break;
default:
throw new Error('Unknown environment.');
}

module.exports = {
entry: './index',
output: {
library: 'createFragment',
libraryTarget: 'umd',
filename: __DEV__
? 'react-addons-create-fragment.js'
: 'react-addons-create-fragment.min.js',
},
externals: {
react: {
root: 'React',
commonjs2: 'react',
commonjs: 'react',
amd: 'react',
},
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': __DEV__ ? '"development"' : '"production"',
}),
].concat(
__DEV__
? []
: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
},
output: {
comments: false,
},
}),
]
),
};
2 changes: 2 additions & 0 deletions addons/react-addons-linked-state-mixin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
react-addons-linked-state-mixin.js
react-addons-linked-state-mixin.min.js
14 changes: 9 additions & 5 deletions addons/react-addons-linked-state-mixin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
"object-assign": "^4.1.0"
},
"scripts": {
"test": "jest",
"prepublish": "npm test"
"test": "TEST_ENTRY=./index.js jest",
"build:dev": "NODE_ENV=development webpack && TEST_ENTRY=./react-addons-linked-state-mixin.js jest",
"build:prod": "NODE_ENV=production webpack && NODE_ENV=production TEST_ENTRY=./react-addons-linked-state-mixin.min.js jest",
"build": "npm run build:dev && npm run build:prod && node ../postbuild.js",
"prepublish": "npm test && npm run build"
},
"files": [
"LICENSE",
Expand All @@ -25,9 +28,10 @@
"react-addons-linked-state-mixin.min.js"
],
"devDependencies": {
"create-react-class": "^15.5.4",
"jest": "^19.0.2",
"react": "^15.4.2",
"react-addons-test-utils": "15.4.2",
"react-dom": "^15.4.2"
"react": "^15.5.4",
"react-dom": "^15.5.4",
"webpack": "^2.6.1"
}
}
63 changes: 47 additions & 16 deletions addons/react-addons-linked-state-mixin/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,40 +12,71 @@
'use strict';

let LinkedStateMixin;
let createReactClass;
let React;
let ReactDOM;
let ReactTestUtils;

// For testing DOM Fiber.
global.requestAnimationFrame = function(callback) {
setTimeout(callback);
// Catch stray warnings
var env = jasmine.getEnv();
var callCount = 0;
var oldError = console.error;
var newError = function() {
callCount++;
oldError.apply(this, arguments);
};

global.requestIdleCallback = function(callback) {
setTimeout(() => {
callback({
timeRemaining() {
return Infinity;
},
});
console.error = newError;
env.beforeEach(() => {
callCount = 0;
jasmine.addMatchers({
toBeReset() {
return {
compare(actual) {
if (actual !== newError && !jasmine.isSpy(actual)) {
return {
pass: false,
message: 'Test did not tear down console.error mock properly.',
};
}
return {pass: true};
},
};
},
toNotHaveBeenCalled() {
return {
compare(actual) {
return {
pass: callCount === 0,
message: 'Expected test not to warn. If the warning is expected, mock ' +
"it out using spyOn(console, 'error'); and test that the " +
'warning occurs.',
};
},
};
},
});
};
});
env.afterEach(() => {
expect(console.error).toBeReset();
expect(console.error).toNotHaveBeenCalled();
});

describe('LinkedStateMixin', () => {
beforeEach(() => {
jest.resetModules();

createReactClass = require('create-react-class');
React = require('react');
ReactDOM = require('react-dom');
ReactTestUtils = require('react-addons-test-utils');
LinkedStateMixin = require('./index');
ReactTestUtils = require('react-dom/test-utils');
LinkedStateMixin = require(process.env.TEST_ENTRY);
});

// https://facebook.github.io/react/docs/two-way-binding-helpers.html#linkedstatemixin-before-and-after
it('should work with valueLink', () => {
spyOn(console, 'error'); // Ignore deprecated valueLink message for now

const WithLink = React.createClass({
const WithLink = createReactClass({
mixins: [LinkedStateMixin],
getInitialState: function() {
return {message: 'Hello!'};
Expand All @@ -70,7 +101,7 @@ describe('LinkedStateMixin', () => {

// https://facebook.github.io/react/docs/two-way-binding-helpers.html#linkedstatemixin-without-valuelink
it('should work without valueLink', () => {
const WithoutLink = React.createClass({
const WithoutLink = createReactClass({
mixins: [LinkedStateMixin],
getInitialState: function() {
return {message: 'Hello!'};
Expand Down