Photo by Sung Jin Cho on Unsplash

In an app that I’m currently working on, I need to copy some large files from local disk over to DigitalOcean Spaces everyday after processing. Because the files are quite large, I need to do it via streaming instead or I will exhaust my VPS’s memory.

Following Laravel’s documentation, I have some codes that look like this:

$path = \Storage::disk('local')->path('data.csv');$file = new \File($path);\Storage::disk('digitalocean')->putFile('archive', $file);

But I would get an error like this and I have no idea why!

Call to undefined method Illuminate\Support\Facades\File::hashName() at vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php:259

If I change to use putFileAs() instead, I would get this error instead:

Photo by Brian McGowan on Unsplash

I love how easy it is to plug in Laravel Scout and Meilisearch and instantly I get a search engine for my app. Searching by keywords is easy and well-documented. Assuming a Movie model, we could just do this and get a list of results.

Movie::search('Star Wars')->get();


But what if we wanted something more specific. We wanted only the Star Wars movies produced after 1990? We can’t do it as such:

Movie::search('Star Wars AND year >1990')->get();

Does that mean Laravel Scout is a no go?

No way!

Here’s how

Meilisearch has a concept of filtering. …

Photo by Joshua Aragon on Unsplash

If you have recently updated to Sublime Text 4, and that you are using SublimePHPCompanion, you may have already noticed how many features such as Find User, Expand Fully Qualified Class Name, Import Namespace etc stopped working.

At first I thought maybe the package needed updating before it can support Sublime Text 4… Turns out that the fix is super simple!

So the reason SublimePHPCompanion stopped working is due to this new setting added in ST4 index_exclude_gitignore. By default it’s set to true, which means the editor would look into our .gitignorefiles and decide whether to index them or not.

AlpineJS is great as a jQuery replacement when you need to perform some simple Javascript operation like opening and closing a dropdown menu. Dropdown menu is now increasingly popular as a UI choice and here we’ll learn how to create the menu easily with AlpineJS and TailwindCSS.

Step 1. Include all necessary assets on our page

We’ll need both AlpineJS and TailwindCSS. For simplicity, we can pull them from the cloud directly:

<link href="^2/dist/tailwind.min.css" rel="stylesheet">
[x-cloak] {
display: none !important;
<script src="" defer></script>

Step 2. Let’s build the basic HTML structure

Without all the stylings, our raw HTML structure with only the essential positional CSS would look like this:


Photo by Piron Guillaume on Unsplash

I just spent the whole day trying to figure out why isn’t my Wireguard working. The client seems to be able to connect but it’s not sending or receiving any data. Doing a wg show doesn’t show that the client is connected. It’s weird!

I was using this script from angristan and I thought maybe I botched the setup during my first trial. So I re-install again with the script. Still no luck.

Then through chance, I realized that… if I disable ufw with ufw disable , my Wireguard client would start working fine!

That’s great now we just have…

Photo by Giammarco Boscaro on Unsplash

If you have created an Elixir Phoenix project without the --no-ecto flag, you will see a lot of warnings and errors regarding databases and ecto down the line.

Here’s how you can disable it.

Go to lib/myapp/application.ex, comment out the following lines:

children = [
# Start the Ecto repository
# Myapp.Repo,

Then look for config/dev.exs and comment out the following lines:

# Configure your database
# config :myapp, Myapp.Repo,
# username: "",
# password: "",
# database: "myapp_dev",
# hostname: "localhost",
# show_sensitive_data_on_connection_error: true,
# pool_size: 10

And to disable for production deployment, go to config/prod.secret.exs, …

Photo by Joshua Aragon on Unsplash

Screen is a very powerful tool to keep a process running in the background while retaining the ability to log out and log back in anytime to check on the output.

Annoyingly I keep forgetting the commands to use screen effectively so here’s a quick reference guide of commands and shortcuts for myself and maybe others.


To start a screen session:

$ screen -S <command>

To list existing screen sessions:

$ screen -ls

To reconnect to a screen session:

$ screen <session_name>

To reconnect to a still attached screen session:

$ screen -rd <session_name>


To detach a screen session: ctrl…

Photo by Sam Moqadam on Unsplash

Say you have a few thousand files that you need to upload to DigitalOcean Spaces totalling up to a few gigabytes from either another Space, your local, or your VPS. And you are wondering what’s the fastest and easiest way to do so.

Previously, I would mount DigitalOcean Spaces using s3fs onto my VPS and started copying files over. But recently when I tried that on close to 5,000 files… It was just too slow.

Then I came across rclone. The speed difference is night and day when compared to s3fs. …

Photo by Leif Christoph Gottwald on Unsplash

If you are new to Elixir Phoenix, on your very first attempt to create the app and run the server with mix phx.server you might have encountered this build error related to Node, Sass, and CSS.

❯ mix phx.server[info] Running SampleWeb.Endpoint with cowboy 2.8.0 at (http)
[info] Access SampleWeb.Endpoint at http://localhost:4000
webpack is watching the files…[hardsource:3aabe17a] Writing new cache 3aabe17a...
[hardsource:3aabe17a] Tracking node dependencies with: package.json, node_modules/*.
Hash: 0efe8912134b66bc238c
Version: webpack 4.41.5
Time: 1806ms
Built at: 03/05/2021 10:42:01 AM
Asset Size…

Photo by Jeremy Bishop on Unsplash

Sometimes, we want to disable a button on click to avoid double-entry submission. This is especially critical on forms that would create new entries when clicked multiple times, we want to prevent that. Here’s where AlpineJS makes things really easy for us.

Assuming that you have already included AlpineJS somewhere on your page:

<script src="" defer></script>

Next we would have a simple HTML structure as such:


To disable the button on click, we’re going to add some AlpineJS magic to this.:

<div x-data="{ buttonDisabled: false }">
<button x-on:click="buttonDisabled = true" x-bind:disabled="buttonDisabled">Save</button>

What we have here is…

Jian Jye

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store