Cover image by Igor Starkov
Recap
Last time, we got through quite a bit:
- created a new GitHub repo
- initiated the repo
- been introduced to JSON
- learned how and why to split up CSS
- added some directories and a landing page
- installed our first package: SASS
- hidden files from version control
- written some SCSS files
- written two
package.json
commands - generated our final CSS
- checked our changes into GitHub
This lesson will be a little more modest in scope. We're going to try and walk and chew gum at the same time.
Previewing our site in a web browser
Wouldn't it be nice to see what our site looks like as we work? And to have the browser refresh automatically whenever we made a change to our code? Guess what - There's A Package For That™!
Type this into the terminal in VS Code:
npm i -D browser-sync
I know we've covered this before, but let's go over some of the new, hip slang:
-
npm
- switch to Node Package Manager mode -
i
- short for "install", so run theinstall
command -
-D
- this is the shorted form of the--save-dev
flag (which ensures that none of the code for this package reaches the live site) -
browser-sync
- this is the package we're installing
What does browser-sync do?
Node comes with a web server built in. browser-sync allows us to spin up a server, open a web browser window and point at it and automatically refresh it, when we've make changes to the source files.
Configuring browser-sync
In package.json
, add a new command to the scripts
node:
"serve": "browser-sync start --server \"dist\" --files \"dist\""
Let's break this down:
-
serve
- this is the name for our new command. We can call it by runningnpm run serve
inside a terminal -
browser-sync
- call the new browser-sync package -
start
- this calls thestart
method within browser-sync which starts the browser-sync server. This might seem redundant (why call browser-sync at all, if you don't want to start it?) but the browser-sync function does other stuff too, such as reloading or setting up an init file -
--server
- this flag specifies that the particular service we want from browser-sync is for it to be a fake server. -
\"dist\"
- this points to the "root" of this particular server. Which isdist
. And because we needed to use nested quotation marks, we had to "escape" them using\
(see escape characters, below) -
--files \"dist\"
- this specifies a location to watch for files other than HTML - for example images.
Remember that because we've added a new node to package.json
, we'll need to make sure that the preceding node has a comma in the right place. VS Code should show you some angry red wiggles, if you've done it wrong. Usually on the following node from where the comma should be.
An escape character is not the same as Harry Houdini. Instead, it's shorthand for "ignore the next thing I type". So let's say you wanted to use a double quotation mark in JSON, you couldn't just do this: ... because if you did so, the strings Instead, you'd need to type: The JSON parser would read the Escape characters
{
"actor": "Dwayne "The Rock" Johnson",
"character": "Harry "King of Handcuffs" Houdini"
}
The Rock
and King of Handcuffs
will escaped their quotation marks and roam free inside the JSON file.
{
"actor": "Dwayne \"The Rock\" Johnson",
"character": "Harry \"King of Handcuffs\" Houdini"
}
actor
value as: quote Dwayne ignore the next character, I'm not finished "The Rock still not finished" Johnson OK, I'm done now, end quote.
Testing browser-sync
Inside a terminal, call your new command using:
npm run serve
It might take a few seconds but eventually a new tab should open in your web browser pointing to your example page. And the text Hello Worm
should appear. It should not be in the Times New Roman font. Note how serve
is still running in the terminal.
You might also see a warning about Windows Firewall blocking some features of this app. Click on Allow access. Browser-sync's cool.Windows firewall warning
Look at how we linked the CSS file in the HTML file (dist/index.html
) using the path /css/main.css
. That initial forward slash means "start from the root of the site". So if we owned the domain "node.com", the CSS file could be found at this URL: https://node.com/css/main.css
. However, if we dragged the HTML file into a browser, that path wouldn't work because Windows boxes think of the root on their file system differently.
This means that browser-sync is opening the local server correctly!
Watching the SCSS
Remember the watch-scss
command we wrote? That isn't currently running. Under Windows, we can't just run two commands at the same time. Until we install another package, that is!
Let's stop serve
from running. Put the terminal in focus and type CTRL + C and agree to stop the server.
Installing npm-run-all
Let's install npm-run-all. Into a terminal, type:
npm i -D npm-run-all
Configuring npm-run-all
This is the new command we need to add to the scripts
node of package.json
:
"start": "run-p serve sass-dev"
(quick angry red wiggles check: is your package.json
valid json?)
We're defining a new command but hang on - it calls run-p
not npm-run-all
. What gives?
Buried deep inside the source of npm-run-all is the run-p
command. run-p
is short for "run in parallel". This means it will run our serve
command and also our sass-dev
command at the same time.
What's in a name?
There's a reason we called this command start
. It's a special name which is assumed to run whatever the default action of our codebase is.
Normally, when we run a command from package.json
, we'd need to type the following into the terminal:
npm run my-command-name-goes-here
However, with start
we just need to do this:
npm start
Let's try it out! Type the above command into a terminal and a browser window should open and display the text Hello Worm
.
Now, open src/scss/_fonts/scss
and add a new typeface to the front of the SCSS variable. Use "Comic Sans MS"
(also add the quotation marks).
It should now look like this:
$font-system: "Comic Sans MS", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
body {
font-family: $font-system;
}
Your page should update with this "classic" meme font as soon as you hit save.
Change of plans
npm-run-all is nice, but I've changed my mind. Have a look at the NPM page for npm-run-all. What do you notice? I'll give you a hint: it was last published (at the time of writing) six years ago.
That is roughly the Victorian period of web development. I've forced you to bolt a steam engine to a spaceship. What can we do about this?
Out with the old
Working with Node is confusing at the best of times so I want you to know we can always reverse a mistake. Let's wrench out the steam engine and watch as it drifts away in space, leaving behind lumps of coal, glittering like asteroids. To uninstall a package from our application, we can type npm uninstall
and then the name of the package. First cancel the start
command with control + c and a terminal, type:
npm uninstall npm-run-all
We'll leave the package.json
unchanged at the moment.
Perhaps, like me, you're suspicious of this. So in Windows Explorer, navigate to your application directory inside GitHub and peek inside the node_modules
folder. There should not be a folder inside there called npm-run-all
.
(try not to think about how much code is already inside node_modules
. It's a black box, remember?)
The nuclear option
Sometimes, your node_modules
folder gets a bit corrupt. I haven't experienced it in a while. Perhaps it was an issue which effected older versions of Node more. But here's the nuclear option: simply delete the whole directory.
Remember that node_modules
won't ever live in your Git repo. So in order to build it up from scratch, in a terminal type:
npm install
This will look through your package.json
file and treat it like a shopping list, tootling round the aisles of NPM and grabbing all the packages we need for a fresh install.
In with the new
OK, so what's the new hotness which replaced npm-run-all? It's called concurrently. We can tell it's the new hotness for a couple of reasons. At the time of writing:
- It has multiple million weekly downloads
- The repo was updated within the last month
Install concurrently by going to your terminal and typing:
npm i -D concurrently
Configuring concurrently
The syntax is similar to npm-run-all, but each different command call should be wrapped in quotes. So the command in package.json
which currently reads:
"start": "run-p serve watch-scss"
... should now read:
"start": "concurrently \"npm run serve\" \"npm run sass-dev\""
(There are those escape characters again. They still look weird but you should get used to them eventually)
Let's test that out! In a terminal, run npm start
. Your "Hello worm" page should load. It should still be in MS Comic Sans. Edit your _fonts.scss
file so that the $font-system
variable is back to normal. The variable should be:
$font-system: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
Hit save and your browser window should automagically update with whatever counts as a normal system font in your world. Yay! Your current setup can walk and chew gum at the same time!
Collaborating
Remember when we hid the directories dist
and node_modules
from Git? We did that because I claimed that a new developer could download our code and derive all the dist
files using just the src
files.
The command we've just added will do this, but only when a developer runs the start
command and happens to edit a SASS file. What about when a new developer joins the project and runs the site for the first time? There won't be any dist
directory and all the files inside.
As we add more functionality to this toolkit, we're going to need to increase what needs to be done when someone first runs the site. We'll also need to add a command which you can run when you want to build all of the files for the production website. Hey! These are the same thing!
Adding a new prepare
command
Let's add a new command to package.json
. Call it prepare
. It should look like this:
{
...
"scripts": {
"sass-dev": "sass --watch --update --style=expanded src/scss:dist/css",
"sass-prod": "sass --no-source-map --style=compressed src/scss:dist/css",
"serve": "browser-sync start --server \"dist\" --files \"dist\"",
"start": "concurrently \"npm run serve\" \"npm run sass-dev\"",
"prepare": "concurrently \"npm run sass-prod\""
}
...
}
prepare
is a special keyword for NPM because this command runs automatically after a developer runs npm install
in their terminal.
This means that our hypothetical second developer will download the repo, then run npm install
and will automatically generate out all the CSS into the dist
directory without realising they're doing it. And that CSS will be based on the latest version of the SCSS.
Perhaps you're wondering why we're using concurrently
- we're running exactly one task. The answer is that you are at the start of a wonderful journey of discovery. During this epic quest, we'll be adding many more commands to package.json
which take files from src
to dist
and compress them in different ways. And we'll be adding these commands onto our new prepare
command as we go. It's going to be really cool, I promise.
Check-in time
Open up GitHub Desktop and check in your work. Remember to push it to GitHub too!
Summary
Here's what we've achieved in this lesson:
- We installed browser-sync so we can see the contents of
dist
in a web browser - Learned about escape characters
- Ran more than one command at the same time
- Learned about the special
start
command name - Installed, then removed a package because we changed our mind
- Learned that if something goes wrong with
node_modules
we can always nuke it and start again
View Chapter 2 code snapshot on GitHub
Quiz
Top comments (0)