Hi guys, this is the second video in the fullstack
Elixir series. In the previous video, we have started our
project by creating a new Phoenix application, setting up a database schema, and implementing
a simple GraphQL API. If you haven't watched that video, you can
either go and watch it, or you can build upon the source code of the application, which
is available on my GitHub account. Now that we have got our backend application
up and running, we can start implementing the cool part, which is to say, the React
application. We will have to configure Webpack to transpile
our JavaScripts and bundle CSS. This is slightly more complicated than using
a generator like create-react-app, but it's not all that hard, because the Phoenix framework
has already generated a simple Webpack config for us, and the file structure is correct. My personal preference is to use Babel with
a plugin for TypeScript. For the styling, I will not be using any CSS
framework, such as Bootstrap or Tailwind CSS. Instead, I will write most of the stylesheets
by hand, and I will be using SASS, which is a CSS preprocessor, to facilitate this task
and add some few neat features, such as variables and nesting. So let's go to the terminal and get our hands
dirty with some actual work. I have "cd"-d into the application directory,
and from here, I will "cd" into the "assets" directory, which is where the frontend files
live. Let's open the Webpack configuration file. I will be using VIM, but you can use any editor
you like. And when you scroll down 20 lines to the "module"
section, you will see that Webpack is already configured to transpile our JavaScripts using
Babel. However, we will still need to configure Babel
to understand React and to transpile TypeScript. So, let's jump to another terminal window,
and in here, I will need to install several libraries. I will install them using yarn. If you don't know what yarn is, it's basically
a package manager, and it's kind of similar to npm. So, if you are using npm, do remember to switch
this "yarn add" to "npm install". I will now add three dev dependencies. These will be two Babel presets and the TypeScript
compiler. So, "yarn add -D @babel/preset-typescript
@babel/preset-react typescript". And now we have to install React and ReactDOM,
so these will be production dependencies. So it's "yarn add react react-dom". Since we are planning to use TypeScript for
React, we still need to add typings for React and for ReactDOM. And now we need to tweak some settings inside
assets/webpack.config.js. One thing we have to do is add a setting section
for module resolution. This way Webpack will be able to find our
modules if they live inside TypeScript or JSX files. So I will jump ten lines up, and you can basically
add this setting anywhere inside the main object, but I tend to add it after the "optimization"
section. So I will add a new section called "resolve",
and inside it, "extensions". And it here, we need to pass four file extensions,
and they will have to be preceded by dots, so it's [".js", ".jsx", ".ts", ".tsx"]. And you have to make sure that the file is
syntactically correct, so after this section, I add a comma. And afterwards, in this "entry" section, our
main file will be converted to TSX, so for now, I will just change it to "./js/app.tsx". And then we also have to change this regular
expression to accept jsx and tsx extensions. So here I will swap this J for a group that
accepts either T or J, and then after the S, I add an X, followed by a question mark,
and this means: "first a dot, then a J or a T, an S, and then an X, which can occur
or not." And I save the file. Another thing we need to set up is in the
Babel configuration file. In the file tree, there is a hidden file called
.babelrc, and in this file, we need to add the two presets we have installed. So here, under presets, I will now add the
names of the two packages: "@babel/preset-typescript" and "@babel/preset-react". And this should be all we need to compile
React components. To see if the configuration is really correct,
let's try to render a "Hello, world" component. Inside of assets/js, I will now create a new
directory, let's call it "TodoApp" in camel case. Inside this directory, I will create a new
file and call it index.tsx. This will be the main file of our React application. In here, let's import React from "react",
and define a simple functional component. const TodoApp =, and here I define an arrow
function that returns an <h1> component with the text "Hello from React!". Now that we have defined our first component,
let's try to actually render it on the page. So when we go to the terminal and try to run
Webpack by typing "yarn watch", we see that we run into an error, because the file "app.tsx"
that we defined as the entry point of our application does not exist. So I will go back to the editor and in the
file tree, I rename the app.js file to app.tsx. There should be no error now, so I go up one
level to the root folder of our Phoenix application and run the server by typing "mix phx.server". And we see that the server is that our Webpack
has started compiling. So when we go back to the browser, we see
that the application still looks like before, and this is expected, because we have never
explictly told the JavaScript to actuall render a component. So I will leave the editor on the left and
the browser on the right, and let me first get rid of all this default boilerplate content. One part of it is in the layout, so I go up
one folder, to lib/todo_list_web/templates/layout/app.html.eex, and when we scroll down, we see that there
is this header, and I'll basically delete all the header and everything that's inside. So on the right, we see that the header has
disappeared. And now I will open the other template, which
is in page/index.html.eex, and I will just delete everything inside this file. When I save it, we see that everything has
disappeared, and this is just as expected. As you know, React needs a container to actually
render, so let me create a <div> for it, and I will give it the id of "TodoApp", and I
close tag. And now we see that it still looks exactly
the same, but when we open the source, we see that there is a div that we can use. So, in the app.tsx file, I will also delete
everything inside, because we will not need it anymore. And in here, I import React from "react",
and then I import ReactDOM from "react-dom", and now I will import TodoApp from "./TodoApp". And now still nothing should change, because
there is no reason to change. And below it, I will write a function that
will actually render the application. document.addEventListener. This means that the function that follows
will be run after the DOM content has been loaded. So there is an event called "DOMContentLoaded",
and as the second argument of this function, I pass an arrow function, and inside this
function, I will first find the container on the page. So const container = document.getElementById,
and I give it the ID of "TodoApp". A common mistake is passing the element's
ID to getElementById with a pound symbol, like this: "#TodoApp". But don't do it, because it's a habit from
jQuery times. So in here, it's just like this: "TodoApp". document.getElementById, and we pass it "TodoApp",
and then if the container does not exist, we will not do anything. And then we can call ReactDOM.render, and
the first thing we need to pass is the TodoApp as a React component, and the second one will
be the container. So when we save it, on the right we see "Hello
from React!". This means that the application is rendering. The last point I would like to cover in this
video is styling. So when we look at the browser window right
now, we see that the text is still nicely styled with the default styling that came
with the Phoenix framework. The way styles are processed in this configuration
of Webpack is that in your JavaScripts, you import a CSS file, and then it goes through
a Webpack plugin that extracts all that CSS and puts it in a separate CSS bundle. However, if we take a look at the app.tsx
file, we can see that there is nowhere that imports this file right now. Let's import this CSS file again. I'm going to the top of the file, and import
"../css/app.css". And
it still looks exactly the same, so let's go to app.css and delete everything that's
inside this file. So right now, we see that there is no styling
anymore. So, just to see if this is working, I will
add some styles, body { margin: 0; padding: 0; font-family: "Helvetica", sans-serif; } And
we see that the styles get applied. And now that this is working, let's set up
SASS. Let's switch back to the terminal. For now let's just close the Phoenix server,
and cd into the assets directory. I will need to install three dev dependencies. So I type "yarn add -D node-sass style-loader
sass-loader". And in here, node-sass is the SASS preprocessor,
and style-loader and sass-loader are two libraries that webpack uses to process our files. So let's flip back to the Webpack configuration. And in this section I will first need to update
this regular expression. Because right now, it only accepts CSS files,
and we know that SASS comes with the extensions .sass or .scss, so first, in the beginning
I add an S, and then I swap the C for a group that accepts either C or A. Then I save the
file. And in this loader configuration, we need
to add style-loader, and this goes before MiniCssExtractPlugin, and in the end, I add
sass-loader. This won't really do anything, because our
file is still in pure CSS. So let's rename the app.css file to app.scss,
and in app.tsx we need to update this import. Let's restart the Phoenix server. And the tab reloaded and we see that it still
looks exactly the same. So let's see if the SASS features actually
work. I flip back to app.scss. Inside the body rule, I will now add a nested
block that says: h1 { font-size: 72px; color: Salmon; }
This should make the text really big and salmon-colored. And I think this concludes today's video. In the following parts, we will install apollo-boost,
configure the GraphQL client, and start implementing some features. So that's it, and if you enjoyed this video,
please like and subscribe, and if you didn't, please leave some feedback in the comments
below. Thank you!