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

[Docs] Error Codes Page #6946

Merged
merged 9 commits into from
Jun 4, 2016
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion docs/Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,15 @@ task :update_acknowledgements do
File.open('_data/acknowledgements.yml', 'w+') { |f| f.write(cols.to_yaml) }
end

desc "copy error codes to docs"
task :copy_error_codes do
codes_json = File.read('../scripts/error-codes/codes.json')
codes_js = "var errorMap = ".concat(codes_json)
Copy link
Collaborator

Choose a reason for hiding this comment

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

codes_js = 'var errorMap = ' + codes_json + ';'

Copy link
Member

Choose a reason for hiding this comment

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

Just go all the way and use interpolation.

codes_js = "var errorMap = #{codes_json};"

Copy link
Contributor Author

@keyz keyz Jun 1, 2016

Choose a reason for hiding this comment

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

How about codes_js = "var errorMap = #{codes_json.chomp};\n"?

File.open('js/errorMap.js', 'w') { |file| file.write(codes_js) }
Copy link
Member

Choose a reason for hiding this comment

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

Can use the same shorthand that you have for read.

File.write('js/errorMap.js', codes_js)

end

desc "build into ../../react-gh-pages"
task :release => [:update_version, :js, :fetch_remotes] do
task :release => [:update_version, :js, :fetch_remotes, :copy_error_codes] do
system "jekyll build -d ../../react-gh-pages"
end

Expand Down
124 changes: 124 additions & 0 deletions docs/_js/ErrorCodesComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/**
* Copyright (c) 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.
*/
/* global React ReactDOM errorMap:true */
'use strict';

function replaceArgs(msg, argList) {
let argIdx = 0;
return msg.replace(/%s/g, function() {
const arg = argList[argIdx++];
return arg === undefined ? '[missing argument]' : arg;
});
}

function segmentify(str) {
const urlRegex = /(https:\/\/fb\.me\/[a-z\-]+)/g;
Copy link
Member

Choose a reason for hiding this comment

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

How is fb.me involved here? I think I'm probably just missing a step here. Ultimately I'd like to not use fb.me for any of this since we have to register the links and I don't think it supports query params.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, sometimes we have a link in a message that points to a gist/doc page (e.g., this one). This function is used to "urlify" the link. See http://keyanzhang.github.io/react/docs/error-codes.html?invariant=119&args="foo"&args="bar" as an example.

I tried to use dangerouslySetInnerHTML, but it didn't work since we have stuff like <%s> in our error messages.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, gotcha. That's cool. I wonder if we should do a pass and make all of our messages markdown-compatible, then we could just convert the message. We already have a bunch of things in backticks with that pattern in mind, so it might "just work" (and we already have a markdown converter that we're using for the home page example).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, but still we need to escape all <%s>s if we wanna dangerouslySetInnerHTML. The ideal one would be a markdown parser that parses a string to an array of React elements with proper keys. I think this is good for now -- as a side effect we also keep the messages exactly the same as the development build.

Copy link
Member

Choose a reason for hiding this comment

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

I think we'd be ok if we did go that route. Maybe v2 :).

FWIW, test your concerns on the example on the home page. It already turns http://website.com into a clickable link (though not with target=_blank) and converts markupy things to be escaped with &lt;. Then it renders with dangerouslySetInnerHTML.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure we want to assume that every link uses fb.me but I suppose it's true currently and we can always change it later so this is fine for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I think making a regex for URLs is either leaky or an overkill...

const matchResult = str.match(urlRegex);
if (!matchResult) {
return str;
}

const segments = str.split(urlRegex);

for (let i = 0; i < segments.length; i++) {
const matchIdx = matchResult.indexOf(segments[i]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

You shouldn't need to run a separate match; with the split regex you have the URLs will always be in odd positions and the text in even positions.

if (matchIdx !== -1) {
const url = matchResult[matchIdx];
segments[i] = (<a key={i} target="_blank" href={url}>{url}</a>);
}
}

return segments;
}

// ?invariant=123&args="foo"&args="bar"
function parseQueryString() {
const rawQueryString = window.location.search.substring(1);
if (!rawQueryString) {
return null;
}

let code = '';
let args = [];

const queries = decodeURIComponent(rawQueryString).split('&');
for (let i = 0; i < queries.length; i++) {
const query = queries[i];
if (query.indexOf('invariant=') === 0) {
code = query.slice(10);
} else if (query.indexOf('args=') === 0) {
args.push(query.slice(5));
}
}

// remove double quotes
args = args.map((str) => str.replace(/^\ *\"(.*)\"\ *$/, '$1'));

return [code, args];
}

function ErrorResult(props) {
const code = props.code;
const errorMsg = props.msg;

if (!code) {
return (
<p>
Copy link
Collaborator

Choose a reason for hiding this comment

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

For this, I'm not sure the example is adding much. Can we just do:

<p>When you encounter an error, you'll receive a link to this page for that specific error and we'll show you the full error text.</p>

No valid query params provided in the URL. Here's an example: {' '}
<a href="/react/docs/error-codes.html?invariant=50&args=%22Foobar%22">
http://facebook.github.io/react/docs/error-codes.html?invariant=50&args="Foobar"
</a>
</p>
);
}

return (
<div>
<h3>Error #{code}</h3>
<code>{segmentify(errorMsg)}</code>
</div>
);
}

class ErrorCodes extends React.Component {
constructor(...args) {
super(...args);

this.state = {
code: null,
errorMsg: '',
};
}

componentWillMount() {
const parseResult = parseQueryString();
if (parseResult != null) {
const [code, args] = parseResult;
if (errorMap[code]) {
this.setState({
code: code,
errorMsg: replaceArgs(errorMap[code], args),
});
}
}
}

render() {
return (
<div>
Copy link
Member

Choose a reason for hiding this comment

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

Do we need the wrapper div?

<ErrorResult code={this.state.code} msg={this.state.errorMsg} />
</div>
);
}
}

ReactDOM.render(
<ErrorCodes />,
document.querySelector('.error-codes-container')
);
15 changes: 15 additions & 0 deletions docs/docs/error-codes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
id: error-codes
title: React Error Codes
Copy link
Collaborator

Choose a reason for hiding this comment

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

I suggested "Error Decoder" and still like that (I think it's cute) but if you prefer this let's just do "Error Codes" without the "React".

permalink: error-codes.html
---

If you're here because you found an error link in your console, read on!
Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of these two paragraphs, can we do:

In the minified production build of React, we avoid sending down full error messages in order to reduce the number of bytes sent over the wire. We highly recommend using the development build locally when debugging your app since it tracks additional debug info and provides helpful warnings about potential problems in your apps, but if you encounter an exception while using the production build, this page will reassemble the original text of the error.


React removes verbose error messages in production to optimize the number of bytes sent over the wire. This page will reassemble your production error messages using an error ID and runtime arguments provided as query params.

----
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's get rid of this hr.


<script src="/react/js/errorMap.js"></script>
<div class="error-codes-container"></div>
<script src="/react/js/ErrorCodesComponent.js"></script>
1 change: 0 additions & 1 deletion docs/docs/ref-10-glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,3 @@ type ReactComponent<TProps> = {

type ReactFunctionalComponent<TProps> = (TProps) => ReactElement;
```