At work I inherited a really old website running on React.
The code was good but by old i mean really old; last commit was 3 years ago and most of the code was 5-6 years old…
So I converted it to TypeScript and ripped out the old babel/webpack build system and installed Vite to handle all the builds.
Everything went pretty smoothly and I got the site up and running with no errors in development mode.
When going to production is when things went sideways. Some pages crashed with the following error:
error: Minified React error #130; visit https://reactjs.org/docs/error-decoder.html?invariant=130&args[]=object&args[]= for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
at vc (vendor.93c27df6.js:23)
at d (vendor.93c27df6.js:23)
at vendor.93c27df6.js:23
at vendor.93c27df6.js:23
at Ts (vendor.93c27df6.js:23)
at ul (vendor.93c27df6.js:23)
at ic (vendor.93c27df6.js:23)
at tc (vendor.93c27df6.js:23)
at ql (vendor.93c27df6.js:23)
at zl (vendor.93c27df6.js:23)
Some quick googling led me to a GitHub issue showing me that I was not alone with this bug.
Package problem number one
It seems that esbuild is checking for __esModule at runtime and rollup (which is used internally in Vite) is not.
So it will happen to any library that has an entry point with: module.exports = require("./module");
Since a file exported this way does not include the ’magic string’ __esModule as checked by generate-exports.js it’s not converted correctly.
In my case I had two librarys acting up; react-datetime which was imported locally like this: import DateTime from "react-datetime"; which worked fine in Vite dev but not production.
The second package with this issue was react-dropzone which in turn used the real culprit; attr-accept
Since the project used an old version (4.x.x, latest version is at the time of writing 14.x.x) and I got other issues upgrading to the latest version I could rule out a PR from me fixing it.
If you can’t stay away from JavaScript, the <details>-tag has a toggle-event that you can subscribe to for updates.
<datalist>
The <datalist> tag specifies a list of pre-defined options and allows users to add more to it. It provides an autocomplete feature that allows you to get the desired options with a type-ahead.
It would be easy to think of this as an alternative to the <select>-tag, but it should be seen as a text-input with built in suggest functionality since the user is not forced to explicitly select one of the given values.
There seem to be some issues when using datalist with a large list (> 512) of options so you might want to consider how many items you put in the list.
<meter>
Use the <meter> tag to visualize a value in a range of numbers. The most common use case I’ve seen is for visualizing the strength in a password.
The <mark>-tag is used to semantically highlight any text for clarity and is maybe best used in search results to mark parts of a bigger text block.
Code:
<p>“Ph’nglui mglw’nafh Cthulhu R’lyeh wgah’nagl fhtagn.”</p>
<p>Legrasse had one point in advance of Professor Webb, for several among his mongrel prisoners had repeated to him what older celebrants had told them the words meant. This text, as given, ran something like this:</p>
<p>“In his house at R’lyeh dead <mark>Cthulhu waits dreaming.</mark>”</p>
<p>And now, in response to a general and urgent demand, Inspector Legrasse related as fully as possible his experience with the swamp worshippers; telling a story to which I could see my uncle attached profound significance. It savoured of the wildest dreams of myth-maker and theosophist, and disclosed an astonishing degree of cosmic imagination among such half-castes and pariahs as might be least expected to possess it.</p>
Legrasse had one point in advance of Professor Webb, for several among his mongrel prisoners had repeated to him what older celebrants had told them the words meant. This text, as given, ran something like this:
“In his house at R’lyeh dead Cthulhu waits dreaming.”
And now, in response to a general and urgent demand, Inspector Legrasse related as fully as possible his experience with the swamp worshippers; telling a story to which I could see my uncle attached profound significance. It savoured of the wildest dreams of myth-maker and theosophist, and disclosed an astonishing degree of cosmic imagination among such half-castes and pariahs as might be least expected to possess it.
Autocapitalize <input>
While not a tag, the autocapitalize attribute can be added to input-elements to force digital keyboards, usually on mobile devices, to behave in a certain way.
It’s good to know that the attribute will not do any changes to the actual value for the input, so it will have no impact when used with a physical keyboard. autocapitalize will make the mobile keyboard change case depending on the value given to the attribute.
Code:
// none: all letter should default to lowercase
<input type="text" autocapitalize="none" />
// characters: ALL CHARACTERS SHOULD BE UPPERCASE
<input type="text" autocapitalize="characters" />
// characters: First letter of each sentence should be uppercase
<input type="text" autocapitalize="sentences" />
// characters: First Letter Of Every Word Should Be Uppercase
<input type="text" autocapitalize="words" />
It should be noted that an input of type url, email, or password will not use autocapitalize.
On bergqvist.it I used styled jsx for styling my components. I preferred that to other css-in-js frameworks (like JSS) because of it actually using CSS syntax instead of JavaScript objects.
// styled jsx example with good old CSS
<style jsx>{`
.label { color: red; font-style: italic; }
.article { padding: 0; }
`}
</style>
//JSS example with CSS as a JS object
const useStyles = createUseStyles({
label: {
color: 'red'
fontStyle: 'italic'
},
article: {
padding: 0
}
})
I like Styled jsx but it has had an issue with FOUC in the last few versions of Next.js though, and with Next 12 I decided to try something new and migrate to CSS Modules instead.
What is CSS Modules?
A CSS Module is a CSS file in which all class names and animation names are scoped locally by default.
So the benefit are the same as css-in-js-frameworks but pure css (or in my case scss) files are used instead of keeping the styling in the javascript files.
I may be old school, but I actually prefer to keep the CSS and JavaScript separated for each other. I can see the benefits of keeping them tightly coupled and can agree that simple, self-contained components probably benefit from this approach, but it gets messy when the component has many styles with media queries.
I also want to use SASS, which is fully supported with CSS Modules in Next.js.
Migrating from styled jsx to CSS Modules
Since Styled jsx use regular CSS it’s actually just a matter of creating the <component>.module.scss-file, importing it into the component and changing the classes
As I already had a global css-file that I imported into my _app.tsx, I really did not have to do anything to get my global classes working. If you want to add a global class in a component file you can add it by using :global() on the class.
When we started using Material UI (version 3) the support for extending the built-in theme was pretty lacking. The theme interface did not handle any additional color settings such as ”success” or ”warn” and trying to extend the theme did not work since parts of interfaces can’t be overwritten.
So instead of extending the theme we used a separate object with corresponding interface to handle the extra colors that we needed. Not ideal but as the colors only were used in a few places we could afford to wait for the support in MUI to get better.
Flash forward a year and the support is here so extend the theme we did! The documentation tells us to use module augmentation to merge our theme with the built-in theme by creating a index.d.ts file and adding our properties in that.
The official way of doing it
So if I want to extend the typography object to accept a secondaryFontFamily I would have to do something like this:
This works well but still uses the Theme interface which makes it harder to know what has been extended.
Our project setup
We package our code in different NPM packages and use Lerna to handle the development environment.
That means that the theme is used over several packages and when we implemented the solution above we quickly realized that we had to add the index.d.ts file in every project, making it very cumbersome to add new attributes in the future.
Back to the drawing board.
A different solution
So we need an interface for our customised theme that we can share with our packages.
There is an official way of using RTL with redux as some people pointed out, but for small quick tests mocking useSelector may still be of use. 🙄
Recently I finally made the switch from Enzyme to React testing library (RTL) which also means that instead of rendering components using shallow like Enzyme proposes, with React testing library the whole component and its child components is rendered, much like Enzymes mount.
The switch to RTL coupled with using hooks instead of HOCs when using Redux got me writing a lot of new component tests but I did run in to some problem when I tried to use the useSelector-hook from Redux multiple times expecting different responses.
The component that I wanted to test as a search component that made calls similar to this:
Which worked fine until I realised that a child component also calls useSelector and therefore crashed. 😱
I knew I needed something that would support all possible selectors that I needed but still could be modified on a test by test basis. I had a mock state ready, but not the method to alter and inject it. Until I ran across jest.fn().mockImplementation…
The solution to my problems
useSelector takes a callback as its argument and all I had to do was to call that callback with a compatible state that would satisfy all my components needs and they would do the rest as implemented.
So in the code above I mock useSelector from the react-redux npm package and replaces it with a function that executes any given callback function with my mocked state as an argument. This is done before every test.
In the second test I create a second mocked state that I want to use for just that test so I override useSelector to make sure it uses my updated state instead of the default mock state.
Parting words
I hope this helped someone to learn a little bit more about how to test their code and what can be achieved with jest and tools like RTL (which is great, try it!)
All typos my own and please leave a comment if you have a question or something does not make sense.
I love RSS-feeds (and still curse Google for cancelling Google Reader) and use them as my main news source for things I find interesting so with this article I would like to help people to add RSS-feeds to their blogs.
If you read my article about how to add a sitemap.xml to your next.js site you will recognise much of the code, it’s pretty much the same base but with slightly different XML-markup.
Creating the page
First off we need a page that can return the XML. I suggest you name it ”rss”, ”feed” or something similar.
In getInitialProps we get our blog posts and set the ”Content-Type”-header to ”text/xml” so the browser knows that should expect XML instead of HTML. We then generate the XML and passes it on to the browser using res.write.
export default class Rss extends React.Component {
static async getInitialProps({ res }: NextPageContext) {
if (!res) {
return;
}
const blogPosts = getRssBlogPosts();
res.setHeader("Content-Type", "text/xml");
res.write(getRssXml(blogPosts));
res.end();
}
}
Generating the base XML for the feed
For the base XML document you will need to add some basic information like the title of the log, a short description, link to your website and the language of the content. Title, link and description are mandatory elements in the RSS specification but add as many optional elements as you find useful.
With the basic stuff out of the way all we need to go is generate some XML for the blog posts and figure out when the blog was updated.
The item element should at least contain a link to the blog post, the date when it was published and the text. You can either opt to put a short description and force the user to come visit your page or put the whole post in the XML.
If you have HTML-markup in your text you need to enclose it within a <![CDATA[${post.text}]]>-tag or HTML encode the text.
While building my blog with Next.js I naturally wanted to support sitemaps because it can supposedly help out the search engines. For my small blog it will not make any difference but for larger sites it’s more important. Google has this to say.
Using a sitemap doesn’t guarantee that all the items in your sitemap will be crawled and indexed, as Google processes rely on complex algorithms to schedule crawling. However, in most cases, your site will benefit from having a sitemap, and you’ll never be penalized for having one.
Page for the sitemap
The first thing we need to do is to create a sitemap.xml.ts page in the ”page”-folder. This will expose a https://yourdomain.com/sitemap.xml url that you can submit to search engines. if you want to you can omit the .xml part and only use /sitemap, Google search console will accept the url anyway.
We want to make sure that we set the Content-Type header to text/xml and to write our xml output to the response stream.
For the site map we want to list all pages on the site, apart from the blog posts we have to add all additional pages that we want the search engines to find.
I have an about page that I add manually together with the index page but if you have many pages I suggest you create an array and add them in a more automated way.
I won’t go into the inner workings of all the properties of a sitemap but I want to mention the <priority>-tag that lets you set a value between 0 and 1 indicating how important you think the page is. <lastmod> is used to indicate when the page was changed.
As mentioned above I want to add the dynamic blog post pages to the site map as well. In the blogPostsXml-function I generate xml for all posts and keep track of when the latest post was posted.
TypeScript has really taken off lately in the React world and rightly so, it’s a great way to keep your code documented and help you keep some errors at bay.
I have worked with TypeScript in a few projects the last few years, all involving Angular in some form but never with React so I had some new challenges in front of me when I started my current project with React and TypeScript.
Functional components
Let us start off easy with a basic functional component:
We create an interface called OwnProps where we define all props we want the component to have.
OwnProps is then used to define the component: React.FC<OwnProps> as well as when we export the component as React.ComponentType<OwnProps> to clearly signal what props are available.
In this basic example it may seem unnecessary but, as we shall see further down, when components get more complex it will save us some headache. This approach will also help negate the following error:
error TS2604: JSX element type ’MyComponent’ does not have any construct or call signatures.
Wrapping another component
In some cases you might want to wrap another component and include that components interface in your own. This is usually the case when working with base components from a library and since we use Material UI (MUI for short)as a base component library I will use that in the example.
The Props type can be seen as the sum of all parts that the component will consist of. In this case we want to use ButtonProps from MUIs Button component and merge it with our own and expose both props to the consumers of the component.
This is still not very advanced but since we use MUI we also use JSS for styling so let us add that to the mix!
Using WithStyles and WithTheme
Since we use MUI we handle styling with JSS and the generated CSS classes are injected via the withStyles HOC. This caused some issues since a classes object containing the class names is injected into your props and to use classes you would need to include that object in your prop type.
Luckily we have the WithStyles type to help us! WithStyles<typeof styles> takes a generic type argument of your style object so you don’t have to worry about it keeping your types DRY.
The addition we’ve done here is adding a PublicProps type and using that instead of the Props type when exporting the component. This is of course because we also want to use WithStyles but not expose it to anyone using the button.
Had we used the Props type instead of PublicProps we would get a pesky TypeScript error complaining about classes property missing.
Redux connect and compose
But what would React be without state handling? We use Redux for this so let us connect MyButton and get the buttonText prop from state instead.
We have not started using hooks for our state so we go with the good old connect. Since we now use both connect and withStyles we need to use compose to merge them.
We create StateProps as return type of mapStateToProps and DispatchProps which types the dispatch function that is returned by default if we don’t add a mapDispatchToProps function. In out case we use Thunk so if you use some other tool you need to use that instead.
I have also added an example of using the MUI theme in the component, this is done by adding { withTheme: true } as a second argument to withStyles. This will inject a theme property into your props so we need to specify that in our Props type using WithTheme from MUI.
TypeScript can be very frustrating when starting out with many errors that are not clear so I hope this article could be of some help or inspiration, it took us a while to settle on a TypeScript pattern that worked for us and helped us mitigate most of the errors that might occur when working with different libraries.
Feel free to leave any suggestions in the comment field.