Programming – closingtags </>
Categories
HTML5 Javascript Linux PHP Programming Python

Remote Debugging Web Apps on iOS from Linux

Debugging #WebApps on #iOS is a super easy if you have a Macbook. If you’re on #Linux, it’s not. This post documents how I got around that limitation by using #OpenSource utilties and tools.

Categories
CSS HTML5 Javascript Programming SvelteKit WordPress

Accessibility for Lazy Developers

I’m lazy and you probably are too. This post talks about a few easy-to-use tools that even the laziest of developers can use to ensure their application is accessible to all.

#a11y #accessibility #automation

Categories
Javascript Programming Svelte SvelteKit

Enabling Persistent Storage in IndexedDB

Exploring how to mark #IndexedDB storage as persistent for an offline first #PWA built with #SvelteKit

Categories
CSS Javascript Programming Svelte SvelteKit

Tailwind CSS + SvelteKit = ❀️ && πŸ’”

In an effort to promote my upcoming book, I created the website https://sveltekitbook.dev. It has all of the information one may want to know before purchasing a copy. Of course, the book is about #SvelteKit so I had to build the site using #SvelteKit. I decided to take the opportunity to learn the latest technology web developers can’t shut up about; #TailwindCSS.

Categories
Javascript Programming Svelte SvelteKit

Why I Quit Writing

In my last post, I prefaced it by saying that I haven’t been posting here often because I’ve been busy. In reality, I only missed a single post back in May so I guess you could say that I haven’t actually quit writing.
(But you’ve already clicked the link and are reading the post so the bait worked, right? Might as well stick around for the rest.) 😎
In fact, I’ve doubled down on the writing because the latest project that has been keeping me so incredibly busy has been…
…writing my first book!
SvelteKit Up and Running
That’s right! An entire book made out of paper and ink like they used to have back in the ye olden days. Of course, there will be digital copies for you technology enthusiasts as well. The book is titled SvelteKit Up and Running: Building High Performance Web Apps with a Next Generation Framework. It is obviously about SvelteKit, the highly performant web application meta framework from the creators of Svelte. I wrote it because I wanted to give others the resource I wish I had when I was learning how to build web apps with Svelte and SvelteKit.
Whether you’re new to JavaScript development and are wondering which framework to pick up first, or are a seasoned developer tired of the bloat that comes with other popular frameworks; this book will teach you the concepts behind the project leading the field in revolutionizing JavaScript development. The examples found throughout the book are concise, practical, and easy to follow along with while still effectively demonstrating how to leverage the various techniques necessary for implementing features commonly found in web applications.
Pre-order

As of this writing, the book is currently trending #3 on Amazon! How wild is that?

If you’re interested in getting a copy (and I hope you are), it’s available for pre-order now at https://packt.link/bVAyJ! The book is scheduled for release on July 28th, 2023.
Want more?
If you’re curious about what it takes to write a book, the process behind it, how I got started, and lessons I learned, then be sure to subscribe to this site’s RSS feed, follow me on Telegram, or find me in the Fediverse. I’ll be posting more updates as well as outlining my experience throughout the entirety of this project!

Categories
Programming Security

Recovering Corrupted .docx Files

Did you know that files with the extension .docx are really just .zip packages?

#LibreOffice #Word #Office

Categories
Javascript Programming Security Server Svelte

2022 Recap

I know its clichΓ© to ask it but I’m going to anyways; where did the year go? It feels like just yesterday, I was writing about setting up a Node & MongoDB with Docker Compose.

#2022 #Recap #FullStack #WebDev

Categories
Automation CSS HTML5 Javascript Linux Mobile PHP Programming Security Server Svelte WordPress

BUY! BUY! BUY!

I’ve been writing on this blog for nearly 9 years and I’ve learned so much since I started. The style and the content have come a long ways and I cringe every time I read old posts thoroughly enjoy seeing how I’ve grown as a developer. I’ve interacted with people that I never would have had the chance to otherwise. It’s been a wonderful learning experience.
While my intentions have always been for this site to exist as a sort of journal/wiki/knowledgebase/playground, I’ve always secretly wanted to become a billionaire tech influencer. And now you can help me achieve that goal by buying my merchandise!
BUY! BUY! BUY!
By purchasing merchandise from my shop, you can support this site financially, by giving me real money that you’ve earned for your “hard work.” While donations are always appreciated, I understand that you may want something in return; something tangible, something you can see and smell, something to keep you comfortable while you cry yourself to sleep. And since nobody actually donates to strangers on the internet, I opened a shop.

All of the designs are completely original and there are many, many more to come. The pricing is affordable for all budgets and will only expand with more options. Be sure to check posts here often by following the social media channels or the RSS feed. There may just be coupon codes hidden in future posts πŸ˜‰.
So if you’re ready to showcase the fact that you know what HTML is and like the look of monospaced fonts, then you should go checkout the new closingtags merch shop. Once you’ve got the closingtags swag (closingswag πŸ€”), be prepared to have people you barely know ask if you “work with computers” or to tell you about their genius new app idea.
Don’t forget to buy, buy, buy!

Categories
Javascript Programming Svelte

Svelte stores in IndexedDB

I know that I just wrote a post about using Svelte Stores with localStorage but very shortly after writing that (and implementing it in my own app 🀦), I came across this blog post from Paul Maneesilasan which explained the benefits of using IndexedDB:

So, the primary benefits to using a datastore like indexedDB are: larger data storage limits (50MB), non-blocking operations, and the ability to do db operations beyond simple read/writes. In my case, the first two alone are enough to switch over.
https://www.paultman.com/from-localstorage-to-indexeddb/
Since I had some fresh ideas for my own app about storing lots of data that could potentially would definitely go over the Web Storage 5-10MB limit, I dug even deeper into the research. In the end, I too decided to make the switch.
Sexy Dexie
The documentation for IndexedDB can be overwhelming. It’s great how thorough it is, but I found it difficult to read. After spending a few hours trying to understand the basics, getting bored, looking at memes, and finally remembering what I was supposed to be doing, I came across a package called Dexie. Dexie is a wrapper for IndexedDB, which means that it will make calls to the database for me; for instance Table.add(item) will insert the item object on the specified table. This greatly reduced my need to build that functionality myself. Since I hate reinventing the wheel (and my brain can only learn so many things in a day), I opted to use this package to manage the database. Plus, Dexie has a handy tutorial for integrating with Svelte and makes managing database versions a breeze.
While the Dexie + Svelte tutorial is great, including Dexie in each and every component that gets and sets data (like the tutorial does) would be cumbersome. It would be far simpler to use Svelte stores across components, and have the stores talk to IndexedDB via Dexie.
Custom Stores
Since IndexedDB; and therefore Dexie, utilize asynchronous APIs, a few things need to be done differently to integrate with Svelte stores. Firstly, we can’t just “get the values” from the database and assign them to a writable store (like we did in the localStorage example) since we’ll be receiving a Promise from Dexie. Secondly, when the data is updated in the store, we also need to update the data in the database; asynchronously.
This is where custom stores come in. In a custom store, we can create our very own methods to manage getting and setting data. The catch is that the store must implement a subscribe() method. If it needs to be a writable store, then it also needs to implement a set() method. The set() method will be where the magic happens.
To get started, follow Dexie’s installation instructions (npm install dexie) and create a db.js file to initialize the database. I’ve added a couple methods to mine to keep database functionality organized:
Note that is generic code sampled from helth app so references to water, calories, and sodium are done in the context of a health tracker.
import { Dexie } from ‘dexie’;
// If using SvelteKit, you’ll need to be
// certain your code is only running in the browser
import { browser } from ‘$app/environment’;

export const db = new Dexie(‘helthdb’);

db.version(1).stores({
journal: ‘date, water, calories, protein, sodium’,
settings: ‘name, value’,
});

db.open().then((db) => {
// custom logic to initialize DB here
// insert default values
};

export const updateLatestDay = (date, changes) => {
if(browser) {
return db.journal.update(date, changes);
}
return {};
};

export const getLatestDay = () => {
if(browser) {
return db.journal.orderBy(‘date’).reverse().first();
}
return {};
};

export const updateItems = (tableName, items) => {
if(browser) {
// .table() allows specifying table name to perform operation on
return db.table(tableName).bulkPut(items);
}
return {};
}

export const getItems = (tableName) => {
// spread all of the settings records onto one object
// so the app can use a single store for all settings
// this table has limited entries
// would not recommend for use with large tables
if(browser) {
return db.table(tableName).toArray()
.then(data => data.reduce((prev, curr) => ({…prev, [curr.name]: curr}), []));
// credit to Jimmy Hogoboom for this fun reducer function
// https://github.com/jimmyhogoboom
}
return {};
}
I won’t go over this file because it’s self explanatory and yours will likely be very different. After you have a database, create a file for the stores (stores.js).
import * as dbfun from ‘$stores/db’;
import { writable } from ‘svelte/store’;

// sourced from https://stackoverflow.com/q/69500584/759563
function createTodayStore() {

const store = writable({});

return {
…store,
init: async () => {
const latestDay = dbfun.getLatestDay();
latestDay.then(day => {
store.set(day);
})
return latestDay;
},
set: async (newVal) => {
dbfun.getLatestDay()
.then(day => {
dbfun.updateLatestDay(day.date, newVal);
});
store.set(newVal);
}
}
}

function createNameValueStore(tableName) {
const store = writable({});

return {
…store,
init: async () => {
const items = dbfun.getItems(tableName);
items.then(values => {
store.set(values);
})
return items;
},
set: async (newVal) => {
dbfun.updateItems(tableName, Object.keys(newVal).map((key) => {
return {name: key, value: newVal[key].value}
}));
store.set(newVal);
}
}
}
export const today = createTodayStore();
export const settings = createNameValueStore(‘settings’);
Here’s break down what this does:

Import the db.js file and any extra functionality added to it.
Import { writable } from svelte/store since we’ve already established that I hate reinventing the wheel.
Create 2 functions; createTodayStore() and createNameValueStore(). Both functions are mostly identical except for the logic they call on the database.
Each function then creates their own store from writable with an empty object as the default value.
Both functions return an object that adheres to the store contract of Svelte by implementing all the functionality of writable, overriding set(), and adding a custom method init().
init() queries the database asynchronously, sets the value of the store accordingly, then returns the Promise received from Dexie.
set() updates the data within the database given to the store and then proceeds to set the store accordingly.
Export the stores.

Accessing the stores
Now that the stores have been created, accessing them isn’t quite as simple as it was when they were synchronous. With a completely synchronous store, svelte allowed access to the data via the $ operator. The stores from localStorage could be accessed or bound simply by dropping $storeName wherever that data was needed. With the new asynchronous stores, calling the custom init()method is mandatory before accessing the data; otherwise, the store won’t have any data! Here’s a simple Svelte component showing how to access the settings store data in the <script> tag and binding to the today store in the markup.
<script>
import { onMount, afterUpdate } from ‘svelte’;
import { today, settings } from ‘$stores/stores’;
import Spinner from ‘$components/Spinner.svelte’;

$: reactiveString = ‘loading…’;

onMount(() => {
settings.init()
.then(() => {
if(‘water’ in $settings) {
reactiveString = `water set to ${settings.water.value}`;
}
});
</script>

{#await today.init()}
<Spinner />
{:then}
<input type=”number” bind:value={$today.water} />
{:catch error}
<p>error</p>
{/await}
<p>{reactiveString}</p>

<Spinner /> source can be found here.
This instance of a reactive variable doesn’t make much sense unless it were tied to another value but the logic remains the same.
Accessing the today store value in the markup is made possible by use of Svelte’s {#await}.

el fin
Is this the best way connect Svelte stores to IndexedDB?
I have no idea. Probably not.
But it does seem to work for me. If you’ve got ideas on how it could be improved, leave a comment. I’m always open to constructive criticism. If you’re curious about the app this is taken from, I’ve previously written about it here. The source code for it can be found on GitHub.
And lastly, if you’ve enjoyed this post or found value in it, consider sponsoring me on GitHub.

Categories
Plugins Programming Themes WordPress

WordPress + Docker

Dear Vagrant,
You’ll always hold a special place in my heart but there comes a time when we have to put the past behind us. We grow, change, and you and I aren’t what we used to be. We’ve grown apart and become so different. There is no doubt that someone out there will love you, but for me; well I’m done with the days of an upgrade to VirtualBox breaking my virtual environment. I’m saying goodbye to your virtual machines taking a whopping 7 seconds to start. Vagrant, I’ve found someone else, and yes; it is Docker.
πŸ’”
If you’ve read any recent posts of mine, you’ll have noticed a distinct lack of information regarding WordPress. It’s not that I dislike WordPress now but given the option of developing with WordPress or not-WordPress, I’d choose not-WordPress. Remembering all of the hooks, the cluttered functions.php files, and bloated freemium plugins has all become so tiresome. That’s not to say that I’ll never work with it again, after all; this blog is powered by WordPress as is more than 1/3 of the web as we know it. Since I’ll never officially be done with WordPress, I should at least find some more modern ways to manage development with it.
Dockerize It
To get WordPress development environment up and running quickly, I use docker-compose. I’ve written about it before over here. It’s incredibly simple since the docker community maintains a WordPress image.
docker-compose.yml
services:
db:
image: mariadb:10.6.4-focal
command: ‘–default-authentication-plugin=mysql_native_password’
volumes:
– db_data:/var/lib/mysql
restart: always
environment:
– MYSQL_ROOT_PASSWORD=somewordpress
– MYSQL_DATABASE=wordpress
– MYSQL_USER=wordpress
– MYSQL_PASSWORD=wordpress
expose:
– 3306
– 33060
wordpress:
depends_on:
– db
image: wordpress:latest
ports:
– “8000:80”
restart: always
volumes:
– ./:/var/www/html
– ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
environment:
– WORDPRESS_DB_HOST=db
– WORDPRESS_DB_USER=wordpress
– WORDPRESS_DB_PASSWORD=wordpress
– WORDPRESS_DB_NAME=wordpress
volumes:
db_data:
For the most part, this file is the same as the one taken from the docker quick start example. Here are couple directives that I made changes to:

ports: I changed these around as I had some other services running from different programs
depends_on: Telling WordPress not to start until the DB has started also prevented some issues where I was seeing the famous “white screen of death”
volumes: set the current working directory to be the WordPress instance as well as created a custom PHP ini file to fix upload size restrictions

uploads.ini
file_uploads = On
memory_limit = 1024M
upload_max_filesize = 10M
post_max_size = 10M
max_execution_time = 600
Placing this uploads.ini file in a directory accessible by the docker-compose.yml let me fix problems with large file uploads.
I got 99 problems and they’re all permissions
This is all well and good but there are some issues when trying to develop locally. For instance, after running docker-compose up -d, I noticed that all files belong to www-data:www-data. This is necessary for the web server in the container to serve the files in the browser at http://localhost:8000. But then I didn’t have write permission on those files so how could I manage them?
I came across a couple of solutions but they each have their drawbacks. For instance, if I set the entire WordPress instance to be owned by my user, then the web server won’t have permission to read or write to files. I could also add my user to the group www-data but even then, I won’t have write permissions until I run something akin to sudo chmod 764 entire_wordpress_dir which isn’t desirable (but is probably the best option so far). The compromise I came up with was setting myself as the owner for all of the WordPress install, and giving WordPress ownership of the uploads directory. It seems that for now, I’ll just have to flip permissions via the CLI.
If you have ideas on how to resolve the permissions issue with WordPress and docker-compose, leave a comment below!