The yield statement is great for representing asynchronous control flow in a linear style, but we also need to do things in parallel. We can't write:
// wrong, effects will be executed in sequence const users = yield call(fetch, '/users') const repos = yield call(fetch, '/repos')
Because the 2nd effect will not get executed until the first call resolves. Instead we have to write:
import { all, call } from 'redux-saga/effects'
// correct, effects will get executed in parallel const [users, repos] = yield all([ call(fetch, '/users'), call(fetch, '/repos') ])
When we yield an array of effects, the generator is blocked until all the effects are resolved or as soon as one is rejected (just like how Promise.all behaves).
To note, the call inside the array need not be covered in yield call.
app.use(function(req, res) { const ip = req.clientIp; res.end(ip); });
It looks for specific headers in the request and falls back to some defaults if they do not exist.
The user ip is determined by the following order:
X-Client-IP X-Forwarded-For (Header may return multiple IP addresses in the format: "client IP, proxy 1 IP, proxy 2 IP", so we take the the first one.) CF-Connecting-IP (Cloudflare) Fastly-Client-Ip (Fastly CDN and Firebase hosting header when forwarded to a cloud function) True-Client-Ip (Akamai and Cloudflare) X-Real-IP (Nginx proxy/FastCGI) X-Cluster-Client-IP (Rackspace LB, Riverbed Stingray) X-Forwarded, Forwarded-For and Forwarded (Variations of #2) req.connection.remoteAddress req.socket.remoteAddress req.connection.socket.remoteAddress req.info.remoteAddress
If an IP address cannot be found, it will return null.
To create a virtual path prefix (where the path does not actually exist in the file system) for files that are served by the express.static function, specify a mount path for the static directory, as shown below:
First, create a file theme.js in your app folder. We would like to give some pinkful color to our app bar:
import { createMuiTheme } from 'material-ui/styles';
import indigo from 'material-ui/colors/indigo';
import pink from 'material-ui/colors/pink';
import red from 'material-ui/colors/red';
export default createMuiTheme({
palette: {
primary: pink,
secondary: indigo // Indigo is probably a good match with pink
}
});
Then, we have to provide the theme above to your app. In order to this, we will encapsulate our app in a MuiThemeProvider.
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import theme from 'xx/xx/theme';
Encapsulate the app in it and pass your theme file in props
export default class Header extends PureComponent {
render() {
return (
Button 1
Button 2
);
}
}
One step further, what if we want to customise all instances of a component type?
To customize a specific kind of material UI components within our app, we will add an overrides property to our theme.js file as described below. You will need to provide to your theme object, the name and class of the component you want to customize. This will be found in the material-ui API documentation.
import { createMuiTheme } from 'material-ui/styles';
import indigo from 'material-ui/colors/indigo';
import pink from 'material-ui/colors/pink';
import red from 'material-ui/colors/red';
export default function StyledComponents() {
return Styled Components;
}
Higher-order component API
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/styles';
import Button from '@material-ui/core/Button';
In the past few years we’ve seen the rise of CSS-in-JS, emerging primarily from within the React community. This, of course, hasn’t been without its controversies. Many people, particularly those already intimately familiar with CSS, have looked on in disbelief.
To get a clearer understanding of why people are choosing to write their styles in JavaScript, we’ll focus on the practical benefits that emerge when taking this approach.
Scoped styles
It’s no secret that architecting CSS effectively at scale is incredibly difficult. When joining an existing long-lived project, it wasn’t uncommon to find that the CSS was the hardest part of the system to figure out.
To counter this, the CSS community has invested heavily in trying to address these issues, making our styles more maintainable with methodologies like OOCSS by Nicole Sullivan and SMACSS by Jonathan Snook—but the clear winner right now in terms of popularity seems to be BEM, or Block Element Modifier, from Yandex.
Ultimately, BEM (when applied purely to CSS) is just a naming convention, opting to limit styles to classes following a .Block__element--modifier pattern. In any given BEM-styled codebase, developers have to remember to follow BEM’s rules at all times. When strictly followed, BEM works really well, but why is something as fundamental as scoping left up to pure convention?
Whether they explicitly say so or not, the majority of CSS-in-JS libraries are following the BEM mindset of trying to target styles to individual UI elements, but implementing it in a radically different way.
What does this look like in practice? When using glamor by Sunil Pai, it looks something like this:
import { css } from 'glamor'
const title = css({
fontSize: '1.8em',
fontFamily: 'Comic Sans MS',
color: 'blue'
})
console.log(title)
// → 'css-1pyvz'
What you’ll notice here is that the CSS class is nowhere to be found in our code. It’s no longer a hard-coded reference to a class defined elsewhere in the system. Instead, it is generated automatically for us by the library. We don’t have to worry about our selectors clashing in the global scope, which means we no longer have to manually prefix them.
The scoping of this selector matches the scoping rules of the surrounding code. If you want to make this rule available to the rest of your application, you’ll need to turn it into a JavaScript module and import it wherever it’s used. In terms of keeping our codebases maintainable over time, this is incredibly powerful, making sure that the source of any given style can be easily traced like any other code.
By moving from mere convention towards enforcing locally-scoped styles by default, we’ve now improved the baseline quality of our styles. BEM is baked in, not opt-in.
Most of the earliest CSS-in-JS libraries attached styles directly to each element, but the critical flaw in this model is that ‘style’ attributes can’t do everything that CSS can do. Most new libraries instead focus on dynamic style sheets, inserting and removing rules at runtime from a global set of styles.
As an example, let’s have a look at JSS by Oleg Slobodskoi, one of the earliest CSS-in-JS libraries to generate real CSS.
When using JSS, you can use standard CSS features like hover styles and media queries, which map directly to the equivalent CSS rules.
These generated classes can then be used instead of hard-coded class strings when generating markup in JavaScript. This pattern works regardless of whether you’re using a full-blown framework, or something as simple as innerHTML.
document.body.innerHTML = `
Hello World!
`
Managing the styles in this way is of little benefit by itself—it’s usually paired with some kind of component library. As a result, it’s typical to find bindings available for the most popular libraries. For example, JSS can easily bind to React components with the help of react-jss, injecting a small set of styles into each component while managing the global lifecycle for you.
import injectSheet from 'react-jss'
const Button = ({ classes, children }) => (
By focusing our styles around components, integrating them more closely at the code level, we’re effectively taking BEM to its logical conclusion. So much so that many in the CSS-in-JS community felt like the importance of extracting, naming and reusing components was being lost in all the style-binding boilerplate.
An entirely new way of thinking about this problem emerged with the introduction of styled-components by Glen Maddern and Max Stoiber.
import styled from 'styled-components'
const Title = styled.h1`
font-family: Comic Sans MS;
color: blue;
`
When applying these styles, we don’t attach a class to an existing element. We simply render the generated component.
Hello World!
While styled-components uses traditional CSS syntax via tagged template literals, others prefer working with data structures instead. A notable alternative is Glamorous by Kent C. Dodds from PayPal.
Glamorous offers the same component-first API as styled-components, but opts for objects instead of strings, eliminating the need to include a CSS parser in the library—reducing the library’s size and performance footprint.
import glamorous from 'glamorous'
const Title = glamorous.h1({
fontFamily: 'Comic Sans MS',
color: 'blue'
})
Whichever syntax you use to describe your styles, they’re no longer just scoped to components—they’re inseparable from them. When using a library like React, components are the fundamental building blocks, and now our styles form a core part of that architecture. If we describe everything in our app as components, why not our styles too?
CSS-in-JS refers to a collection of ideas to solve complex problems with CSS. Since it is NOT a particular library, different libs might solve a different subset of problems and use different approaches, depending on their implementation details.
However, all implementations have in common that they tackle the problems using APIs instead of convention and they leverage JavaScript as a language for styles authoring.
Lack of modules
CSS historically never had actual modules, neither did JavaScript. Requirements for web applications evolved and JavaScript has added a module system. First in the form of a bolt-on solution (CommonJS), later as a standard, statically analyzable module system known as ECMAScript Modules (ESM).
The reasoning behind modules applies to both JavaScript and CSS: to be able to hide implementation details by exposing only public APIs. We need to be able to decouple subsystems of an application explicitly so that changing code becomes more predictable.
Lack of scoping
We know CSS always had a single global namespace, for example, a class can be added to any element, a tag selector can target any element in the document. CSS was initially created to style documents and there was no need for components. The entire page was styled as one big chunk and it usually didn’t involve many people working on it. Since then the complexity of many sites has dramatically increased and this is the main reason why many CSS methodologies were created. None of the conventions is easy to establish and consistently enforce when many people contribute to a project over the years.
Less (which stands for Leaner Style Sheets) is a backwards-compatible language extension for CSS. This is the official documentation for Less, the language and Less.js, the JavaScript tool that converts your Less styles to CSS styles. Because Less looks just like CSS, learning it is a breeze.
Variables
@width: 10px;
@height: @width + 10px;
#header {
width: @width;
height: @height;
}
Mixins
Mixins are a way of including ("mixing in") a bunch of properties from one rule-set into another rule-set. So say we have the following class:
The resulting code is more concise, and mimics the structure of your HTML.
You can also bundle pseudo-selectors with your mixins using this method. Here's the classic clearfix hack, rewritten as a mixin (& represents the current selector parent):
Streaming of audio, video or other data. Getting network information such as IP addresses and ports. Exchanging of this information with other WebRTC clients (peers) to enable connection even through NATs and firewalls. In case of error reporting, initiation, session closing and coordinating with signaling communication. Communicating with streaming video, audio or data. Exchange of information about media and client capability such as resolution and codecs.
The above functions are been implemented by WebRTC by employing some main APIs listed below: MediaStream (aka getUserMedia) RTCPeerConnection RTCDataChannel
Below is a close look at these APIS MediaStream
getUserMedia or MediaStream takes the access to data streams for example from user’s camera and microphone. MediaStream is available in Chrome, Firefox and Opera. MediaSream API represents synchronized streams of media. This can be well-explained that a stream taken from camera and microphone input has synchronized video and audio tracks. Each MediaStream has an input, which might be a MediaStrem generated by navigator. getUserMedia(), and an output might have been passed to a video element or an RTCPeer Connection.
getUserMedia() method takes three parameters:
A constraint’s object. Success callback which, if called, is passed a MediaStream. Failure callback which, if called, is passed an error object.
Each MediaStream has a label, such as ’Xk7EuLhsuHKbnjLWkW4yYGNJJ8ONsgwHBvLQ’. An array of MediaStreamTracks is returned by the getAudioTracks() and getVideoTracks() methods.
For the simpl.info/gum example, stream.getAudioTracks() returns an empty array (because there’s no audio) and, assuming a working webcam is connected, stream.getVideoTracks() returns an array of one MediaStreamTrack representing the stream from the webcam. Each MediaStreamTrack has a kind (‘video’ or ‘audio’), and a label (like ‘FaceTime HD Camera (Built-in)’), and represents one or more channels of either audio or video. In this case, there is only one video track and no audio, but you can easily imagine with use cases where there are more: for example, a chat application that gets streams from the front camera, rear camera, microphone, and a ‘screenshared’ application.
getUserMedia can also be added in Chromium-based apps and extensions. Adding audioCapture and/or videoCapture permissions enables permission to be requested and granted only once, on installation. Thereafter, the user permission for camera or microphone access is not asked.
Similarly, pages using HTTPS: permission only has to be granted once for getUserMedia(). Very first time an Always Allow button is displayed in the info-bar of the browser. It is always required on enabling MediaStream for any streaming data source not just a camera or microphone. This enables streaming from disc or from arbitrary data sources such as other inputs and sensors. Note that getUserMedia() must be used on a server, not the local file system, otherwise a PERMISSION_DENIED: 1 error will be thrown.
2. RTCPeerConnection RTCPeerConnection: Audio or video calling holds the extension of encryption and bandwidth management. It gets supported in Chrome (in desktop and Android both), Opera (on desktop and Android) and of course in Firefox too. RTCPeerConnection is implemented by Chrome and Opera as webkitRTCPeerConnection and by Firefox as mozRTCPeerConnection. There’s an ultra-simple demo of Chromium’s RTCPeerConnection implementation at simpl.info/pc and a great video chat application at apprtc.appspot.com. This app uses adapter.js, a JavaScript shim maintained by Google, that abstracts away browser differences and spec changes.
RTCPeerConnection is the WebRTC component that handles stable and efficient communication of streaming data between peers.
RTCPeerConnection safeguards web developers from the myriad complexities. The codecs and protocols used by WebRTC takes care of huge amount of work to make real-time communication even over unreliable networks:
Packet loss concealment
Echo cancellation
Bandwidth adaptivity
Dynamic jitter buffering
Automatic gain control
Noise reduction and suppression
Image ‘cleaning.’
WebRTC Signalling, session control, network and media information
WebRTC uses RTCPeerConnection to communicate streaming data between browsers. Along with this it also needs a mechanism to coordinate communication and to send control messages. This process can be defined as a signaling. One should know that signaling is not part of the RTCPeerConnection API.
developers can choose whatever messaging protocol they prefer, such as SIP or XMPP, and also an appropriate duplex (two-way) communication channel.
WebRTC needs four types of server-side functionality:
User discovery and communication. Signaling. NAT/firewall traversal. Relay servers in case peer-to-peer communication fails.
RTCDataChannel: peer-to-peer communication of generic data. The API is supported by Chrome 25, Opera 18 and Firefox 22 and above.