Control your OS with Next.js Only
In this article I will show you how to quickly write an application that (at some level) allows you to control your operating
system using next.js without installing anything.
Disclaimer
At the beginning of this article we are starting with a short story about how we came up with using it for such an app, what options we considered and some social butterflying. If you want, you can jump straight to the tutorial section by clicking here. Also this article is aimed more at novice programmers.
Disclaimer, disclaimer
At the beginning I go through setting up the basic project next, if you get it then go on to step-3
It could be a good idea to replace php or other back-end technologies with Next.js
I recently started mentoring a junior. The boy spent a few years in some wordpress templates, marketing
automation and such things and now he can’t find a job even as a junior developer. We came up with an idea for an
application we are building that will impress when deployed but also aims to fill in its gaps in CS foundations and make
it rect / next / react native. And we had our call session, during which we discussed some ways of styling (styled jsx
vs styled components vs css/scss) and at some point the mentor of our program, Pawel – a devops specialist and
former C# programmer, texted me:
“Listen up man, I wrote an app recently for taking notes but I don’t understand the front, I did it in php – I’m not even sure why, it php connects to the C# executable but I don’t understand php much, it seems outdated, it’s hardlyscaled. Could you help me start rewriting this front to typescript?”
We were in the middle of the call with me mentee I thought it would be a good idea for him to also learn something about other technologies and trade-offs so we joined Pawel to the conversation. Then he continued:
Reasoning behind this simple quick choice
The application is simple, like a TODO with a few additional functionalities, such as saving folders to disk, creating files,
pushing it to the repository in the future, printing pdf etc etc.
He also wanted it to be able to keep it locally on windows, but sometimes when he is in a cafe, on the
phone he could start using it as well, he did not want to use any databases at this moment, because we wanted something plain and simple for now, not searching whole internet with technologies that will incorporate history feature to for example mongodb.
Tech stack that we could go for
We considered the following options (considering technologies that we are familiar with and are relatively safe): react-native. Well, you know, just a native app, device storage +
pushing it to different places. But with react native qw would later have to rewrite at least some code, for example, to react native for web. What’s more react, preact, inferno or other next.
The option that came to our mind was PWA, and here again react, next and a number of other technologies. But we wanted something quickly, now.
I told him: listen NextJs is SSR. So all templates, js are pushed to the light of day by node.js. Node, on the other hand, is a server environment.
However, if you are writing something locally, the server is simply your computer. Pawel said that so far it is how it’s being handled now using PHP. That he just serves the php app on localhost and uses it anyway that way, so that’s enough for him. The idea was
to do something modern quickly, which would later be easily deployable.
Finally, let’s write some simple Next.js code!
Prerequisites:
Installed node.js
Optionally yarn
Yarn it is like a superset for npm a bit faster and allows you to create workspaces
directory and aliases. In the case of ts and eslint, I let it go for demo purposes, it will be faster.
Step 1 – scaffolding Next.js project from scratch
We put up a new application. I’d recommend keeping your projects close to your windows/macos home drive, e.g. this would be c/projects. On my mac it’s karpinski94/projects.
Naturally we do cd
to our projects directory
and then we run:
yarn create next-app
npx (Node Package Execute) will trigger scaffolind our next Next.js app.
If you would like to you can look around online for some fancy templates including some useful tools like, linting, pre/post-commit hooks, commitizen, blocking manager yarn /npm only and so on to keep up with the best practices
Next will ask you for a few things like application name, if you want typescript, eslint etc.
directory and aliases. In the case of ts and eslint, I let it go for demo purposes, it will be faster.
Step 2 – Running our newly created Next.js project
Now we can go to our name-of-your-project by cd
‘ing there and running
code .
This should open our project in new window of VSC.
After that you can just run
yarn dev
Then click ctrl / cmd + right click on the url localhost:300 spited out in the console to see your new Next.js application:
If something doesn’t work at this point, the first thing that you will not lose much on doing it’s trying reinstalling the dependencies by running ‘yarn‘ or
deleting the folder node_modules and again runing yarn, or just trying creating new project again.
Step 3 – Writing first lines of front-end Next.js code
Firstly lets go to the index file of our application. It would be: …/projects/name-of-your-project/ src/pages/index.js
and remove all the sections that present Next.js. They should be in between of <main> </main> tags.
In this tutorial I’m leaving everything else, because maybe you will want to develop your app, but describing everything what you see around would be outside of the scope of this article.
Your code in the src/pages/index.js file may look like this right now:
export default function Home() {
returns (
<>
<head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="icon" href="/favicon.ico" />
</head>
<main className={styles.main}>
</main>
</>
) }
Let’s add some button that will let us to create our directories. The button is only for demonstration purposes, so it is styled inline, only to the point that it can be seen.
export default function Home() {
returns (
<>
<head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="icon" href="/favicon.ico" />
</head>
<main className={styles.main}>
{/* New Button */}
<button style={{
padding: '20px 40px',
background: 'lightgreen',
color: 'black'
}}
onClick={createDirectory}>
Create Directory
</button>
{/* New Button */}
</main>
</>
) }
Next.js has a great routing system that correlates the structure folders with the urls of individual endpoints and the base application already provides us with a ‘test’, one you can find it here: /src/pages/api/hello.js
To keep it quick and simple, we will not change too much here, and just use it.
We can see from the hello.js file there is a function named handler, the function as the name suggests ‘handles’ requests that come to the corresponding (automatically created route), for this case it is http://localhost:3000/api/hello:
If you clicked to the link above, you can see this:
The JSON returned by our API. Then so far everything works!
Now let’s go back to our front-end, concretely to the function that will hit this enpoint.
We need to handle the handler: we create a function that will shoot our
api asking to create a folder, to make it easy we will use the built-in fetch
.
The first fetch parameter is the url of the endpoint to which we will hit on the backend.
In the home component we write the following function:
const createDirectory = () => {
fetch('/api/hello').then(() => {
console.log('Our endpoint works!')
})
}
Remember about bidning it with our button, for future usage:
export default function Home() {
const createDirectory = () => {
fetch('/api/hello').then(() => {
console.log('Our endpoint works!')
})
}
return (
<>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<button style={
{
padding: '20px 40px',
background: 'lightgreen',
color: 'black'
}
{/* createDirectory function*/}
} onClick={createDirectory}>
Create Directory
</button>
</main>
</>
)
}
Now, just for testing purposes, we could go to the homepage of our application: localhost:3000.
If you are using chrome or firefox you could launch the developer tools with F12, go to console section and press our green button, you should get a log like this:
It means that we’re half way through.
Step 3 – Writing our simple Next.js back-end
Now, when we’re sure that our front-end cooperates with our back-end. We go to the src/pages/api/hello.js
file and replace handling the response (res) we will create a directory.
For this purpose we will use the fs (file system) library, that allows us to manage files on our os.
It is a built-in node.js module, so we do not need to install anything for this purpose.
Besides our handler let’s create a helper function that will create mentioned directory for us:
async function createDirectoryOnDesktop(directoryName) { }
At this point I should to highlight that the function should be asynchronous, as we don’t want our directory creation operation to block other operations, that are being handled in the main js thread simultaneously. More about it you can learn here.
Another step that we have to take it’s to figure out where our directories will be saved, for this we will use process.env
“process. env – global variable injected by the Node at runtime for your application to use. It represents the state of the system environment your application is in when it starts”
source:google
const desktopPath = `${process.env.HOME}/Desktop/${directoryName}`;
Here I’m just declaring variable that will keep a path to my desktop at the end adding the name of the folder that we will create.
Now let’s get fs to work and create a “dir”.
async function createDirectoryOnDesktop(directoryName) {
const desktopPath = `${process.env.HOME}/Desktop/${directoryName}`;
await fs.mkdirSync (desktopPath, () => {
console.log('Direcotry successfully created')
});
}
Last step is to call our ‘helper function’ in the endpoint handler:
export default function handler(req, res) {
// Just giving the directory some name by passing 'New Directory' string
createDirectoryOnDesktop('New Directory');
}
async function createDirectoryOnDesktop(directoryName) {
const desktopPath = `${process.env.HOME}/Desktop/${directoryName}`;
await fs.mkdirSync (desktopPath, () => {
console.log('Direcotry successfully created')
});
}
Finally – let’s test it
After saving all the files let’s give it a run. Go back to http://localhost:3000/ in your browser. You may also open developer tools, to check whether callback was triggered as well, and keep an eye on your Desktop directory.
Click the button and 3, 2, 1 … voilà!
For creating files you can just check some of the node’s writeFile functions here.
Summary and additional steps to take with Next.js and other frameworks
In this 5-minute tutorial, you learned how to create folders and files on your computer using Next.js.
You were introduced to fs
library but you may want to build something more powerful!
Similar options are: fs-extra
, graceful-fs
, or maybe you would like to play around with JSON files, using jsonfile
or even memory with memfs
.
It’s important though to note that although it’s possible to build a back-end using Next.js, it has limitations and it’s not recommended for fully-fledged back-end applications.
For that purpose, it’s better to use other technologies like express
or more ‘progressive’ nest
.
This tutorial was a quick demonstration for beginners, but it’s important to keep in mind the principles of scalability, testability, security, readability, and others when developing your application.
I hope you enjoyed it!
Thanks,
PK
Senior Software Engineer with over 7 years of experience and entrepreneurial background. Most often, apart from delivering good quality code on time, responsible for introducing good practices, teaching programmers and building team bonds andestablishing communication on the line of development-management. Privately Kākāpō and Wombat enthusiast, traveler and retired acrobat.