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

Introduce React, TypeScript, TSLint and React-StyleGuidist #2219

Merged
merged 23 commits into from
Apr 6, 2018

Conversation

scottnonnenberg-signal
Copy link
Contributor

@scottnonnenberg-signal scottnonnenberg-signal commented Apr 4, 2018

Quite a bit of change here.

First, the basics:

  • New dependencies were added: react, typescript, tslint, and react-styleguidist
  • A new npm script: transpile. It uses typescript to process .tsx files in js/react, putting .js files next to the original file. It's part of the watch functionality of grunt dev as well as the default task run with just grunt (used to build the app prior to release). A lighter-weight to get watch behavior when just working on React components is to run yarn transpile --watch.
  • yarn run clean-transpile will remove generated .js files

Style guide via react-styleguidist. Example site: https://react-styleguidist.js.org/examples/basic/

  • Start with yarn styleguide
  • Component.md files right next to the .tsx file
  • jsdoc-style comments are picked up and added to the generated part of the styleguide - the overall summary and a table listing methods and properties of the component
  • It has hot-reloading!
  • It uses webpack, which means that our app now pulls in webpack though we don't use it to generate anything for the production app.
  • I did a bunch of work to enable the use of Backbone views in this context, which will allow us to move smoothly from the old world to the new. First, add all the permutations in the old way, and then slowly start to re-render those same views with React.

A bit of dependency cleanup to enable use in React components:

  • moment was moved from our Bower dependencies to our npm dependencies, so it can be used in React components not running in a browser window.
  • i18n was moved into the new commonjs format, so it can be used in React components even if window is not available.

Lastly, a bit of Gruntfile cleanup:

  • Removal of Chrome App-era modifications of background.js
  • Make jshint/jscs watch more targeted, since more and more we'll be using other tools

npm run transpile
  Works on files under js/react/
  Outputs files right next to the .tsx file

This is part of our `grunt dev` task, as well as the default grunt task,
which does everything else necessary to get a raw git checkout ready to
run.
Due to a number of hacks, the style guide can be used to show Backbone
views. This will allow a smooth path from the old way of doing things to
the new.
We also fully set up i18n and put it on util as well as making
it available on windows.i18n for Backbone views.
Copy link
Contributor

@gasi-signal gasi-signal left a comment

Choose a reason for hiding this comment

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

First batch of comments. Super excited about this — nice work!!

Happy to discuss any details / style questions in person during standup 😄

.eslintignore Outdated
js/views/**/*.js
test/*.js
test/models/*.js
test/views/*.js
/*.js

# typescript-generated files
js/react/**/*.js
Copy link
Contributor

Choose a reason for hiding this comment

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

👏

.eslintignore Outdated
# ES2015+ files
!js/background.js
!js/backup.js
!js/database.js
!js/logging.js
!js/i18n.js
Copy link
Contributor

Choose a reason for hiding this comment

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

🎉

Gruntfile.js Outdated
'!js/modules/**/*.js',
'!js/views/conversation_search_view.js',
'!js/react/**/*.js',
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor: Could we try and keep 🔡 order in such lists to make them easier to scan and avoid duplicates? I often use Sublime Text‘s Sort Lines command 😄

return content;
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🎆

tasks: ['jshint']
},
style: {
files: ['<%= jscs.all.src %>', './js/**/*.js'],
files: ['<%= jscs.all.src %>'],
Copy link
Contributor

Choose a reason for hiding this comment

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

In the past, I’ve liked using git ls-files to only target files we are actually tracking but I know this can break down in places where we don’t have Git. In our case, we even have Git on CI though, right? Would you be open to that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure what you're suggesting here. We've already specified, in detail, what the jscs task applies to, so we'll be using that for the watch.

Copy link
Contributor

Choose a reason for hiding this comment

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

Apologies if I wasn’t clear. I meant that we often reference js/**/*.js but that includes all files in the repo, regardless of whether they’re tracked in Git or not. When working on a new feature, one can have JS files in the project that haven’t been checked in but still trigger lint errors, etc.

</li>
);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

❤️

<div className="bubble">
<div className="sender" dir="auto" />
<div className="attachments" />
<p className="content" dir="auto">
Copy link
Contributor

Choose a reason for hiding this comment

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

Curious: What’s our guideline for setting dir attribute? The following article suggests setting it where user enter data: https://www.w3.org/International/questions/qa-html-dir Do we set it here because our app is localized and the templates may be filled with either LTR or RTL text? I don’t have a lot of experience with bidi compatibility 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Pure history. Not really sure what the reasoning is there. I just copied what messages are generating today!

@@ -0,0 +1,78 @@
import React from 'react';

interface IProps {
Copy link
Contributor

Choose a reason for hiding this comment

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

Haha, this might be contentious but the TypeScript community has a convention not to use I prefixes for interfaces:

Since we seem to agree to prefer not using classes, this shouldn’t be a big issue for us. Let’s discuss this in person 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed! I only did it because tslint defaulted that way.

this.el = element;
this.setup();
};
this.setup = this.setup.bind(this);
Copy link
Contributor

@gasi-signal gasi-signal Apr 5, 2018

Choose a reason for hiding this comment

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

Minor: If we use static initializers, we can avoid the manual binds (note the = assignment), e.g.

private handleClick = () => {
  this.handleUserLogin({isNew: false})
}

We used this extensively on previous team with great success! (we might have to enable some TSC option for it though, IIRC)

/**
* Corresponds to the theme setting in the app, and the class added to the root element.
*/
theme: 'ios' | 'android' | 'android-dark';
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

@gasi-signal gasi-signal left a comment

Choose a reason for hiding this comment

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

LGTM! Really excited about this — nice work and thanks for starting this 🎉

super(props);

this.el = null;
this.view = null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor: You can initialize instance properties inline using static initializers:

protected el: Element | null = null;
protected view: IBackboneView | null = null;


// TypeScript wants two things when you import:
// 1) a normal typescript file
// 2) a javascript file with type definiitions
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor typo: definiitions --> definitions

/**
* Provides the parent elements necessary to allow the main Signal Desktop stylesheet to
* apply (with no changes) to messages in this context.
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

Love this! Thanks for documenting.

* Provides the parent elements necessary to allow the main Signal Desktop stylesheet to
* apply (with no changes) to messages in this context.
*/
export class MessageParents extends React.Component<IProps, {}> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor: How about *Container or *Provider to align with Redux concepts?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!



// Required, or TypeScript complains about adding keys to window
const parent = window as any;
Copy link
Contributor

Choose a reason for hiding this comment

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

Grr, I hate when that happens. I think there are ways to define the new props but I’d have to do some research.

{
// To test handling of attachments, we need arraybuffers in memory
test: /\.(gif|mp3|mp4|txt)$/,
loader: 'arraybuffer-loader',
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice find! 👀

Copy link
Contributor

@gasi-signal gasi-signal left a comment

Choose a reason for hiding this comment

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

LGTM 👍 Just found one typo (I think)

@@ -1,4 +1,4 @@
Rendering a real `Whisper.MessageView` using `<util.MessageParents />` and
Rendering a real `Whisper.MessageView` using `<util.ConversationContextProvider />` and
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor: ConversationContextProvider --> ConversationContext (I think)

@gasi-signal
Copy link
Contributor

Last two commits LGTM 👍

Split out test-specific and general utility react components too.

And moved our test/legacy* files for the Style Guide into a styleguide/
subdirectory of test/.

I think we'll be able to live in this directory structure for a while.
Copy link
Contributor

@gasi-signal gasi-signal left a comment

Choose a reason for hiding this comment

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

Looking good 🚢

<!-- When making changes to these templates, be sure to update these two places:
1) test/styleguide/legacy_templates.js
2) test/index.html
-->
Copy link
Contributor

Choose a reason for hiding this comment

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

👏 👏 👏 Super helpful!

@@ -17,14 +18,14 @@ window.Signal.Migrations = {
getPlaceholderMigrations: () => {},
};

window.Signal.React = window.Signal.React = {};
window.Signal.React = {};
Copy link
Contributor

Choose a reason for hiding this comment

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

❤️

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reminds me - perhaps this should be window.Signal.Components?


window.Whisper.View.Templates = {
hasRetry: `
{{ messageNotSent }}
<span href='#' class='retry'>{{ resend }}</span>
{{ messageNotSent }} <span href='#' class='retry'>{{ resend }}</span>
Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, one thing you might notice is that since React doesn’t output spaces in the HTML, we might have to tweak certain paddings and margins in places! 😄 See: https://github.com/gasi/Signal-Desktop/pull/1/files#r165859574

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These aren't rendered with React... yet. Duly noted, however!

Copy link
Contributor

@gasi-signal gasi-signal left a comment

Choose a reason for hiding this comment

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

LGTM 👍

SignalReact.Message = Message;
SignalReact.Reply = Reply;
SignalComponents.Message = Message;
SignalComponents.Reply = Reply;
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor: What if we did the following?

parent.Signal.Components = {
  Message,
  Reply,
};

@scottnonnenberg-signal scottnonnenberg-signal merged commit c6c3b65 into development Apr 6, 2018
@scottnonnenberg-signal scottnonnenberg-signal deleted the react-ts-styleguide branch April 6, 2018 15:13
scottnonnenberg-signal added a commit that referenced this pull request Apr 13, 2018
Fixed: Conversation message preview would sometimes continue to show after message disappeared (1206b3c)

Improve URL Auto-Linking In Messages (#2240)

Redact More Variants Of Paths In Stack Traces (#2229)

Dev: Introduce React, TypeScript, TSLint and React-StyleGuidist (#2219 and #2232)
scottnonnenberg-signal added a commit that referenced this pull request Apr 16, 2018
Receive quoted replies (#2244)

iOS theme: one bubble for both attachment and message contents (#2244)

Improve URL Auto-Linking In Messages (#2240)

Redact More Variants Of Paths In Stack Traces (#2229)

Fixed: Conversation message preview would sometimes continue to show after message disappeared (1206b3c)

Dev: Introduce React, TypeScript, TSLint and React-StyleGuidist (#2219 and #2232)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants