diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js index b51cda8..3f4fc8d 100644 --- a/docs/.vitepress/config.js +++ b/docs/.vitepress/config.js @@ -13,7 +13,8 @@ export default { '/wish/': wishGuide(), '/create-sails/': createSailsGuide(), '/inertia-sails/': inertiaSailsGuide(), - '/mail/': mailGuide() + '/mail/': mailGuide(), + '/boring-stack/': boringStackGuide() }, sitemap: { hostname: 'https://docs.sailscasts.com' @@ -31,9 +32,7 @@ export default { [ 'script', { - src: 'https://cdn.usefathom.com/script.js', - 'data-site': 'OTDOQLCI', - 'data-spa': 'auto', + src: 'https://tinylytics.app/embed/vL3m1tsfEzLruHrKLMHB.js', defer: '' } ] @@ -264,3 +263,64 @@ function mailGuide() { } ] } + +function boringStackGuide() { + return [ + { + text: 'Introduction', + collapsed: false, + items: [ + { text: 'Why the name', link: 'boring-stack/why-the-name' }, + { text: 'Who is it for', link: 'boring-stack/who-is-it-for' }, + { + text: "What's in the stack", + link: 'boring-stack/whats-in-the-stack' + }, + { text: 'Getting started', link: 'boring-stack/getting-started' } + ] + }, + { + text: 'The Basics', + collapsed: false, + items: [ + { text: 'Routing', link: 'boring-stack/routing' }, + { text: 'Navigation', link: 'boring-stack/navigation' }, + { text: 'Redirects', link: 'boring-stack/redirects' }, + { text: 'Error handling', link: 'boring-stack/error-handling' }, + { text: 'Sharing data', link: 'boring-stack/sharing-data' } + ] + }, + + { + text: 'Guides', + collapsed: false, + items: [ + { text: 'Authentication', link: 'boring-stack/authentication' }, + { text: 'Authorization', link: 'boring-stack/authorization' }, + { text: 'Database', link: 'boring-stack/database' }, + { text: 'Email', link: 'boring-stack/email' }, + { text: 'Session', link: 'boring-stack/session' } + ] + }, + { + text: 'Deploy', + collapsed: false, + items: [ + { + text: 'Render', + link: 'boring-stack/render' + } + ] + }, + { + text: 'Configuration', + collapsed: true, + items: [ + { + text: 'Type checking JS files', + link: 'boring-stack/type-checking-js-files' + } + ] + } + ] +} diff --git a/docs/boring-stack/authentication.md b/docs/boring-stack/authentication.md new file mode 100644 index 0000000..ae66377 --- /dev/null +++ b/docs/boring-stack/authentication.md @@ -0,0 +1,33 @@ +--- +title: Authentication +titleTemplate: The Boring JavaScript Stack 🥱 +description: Authentication in The Boring JavaScript Stack +prev: + text: Sharing data + link: '/boring-stack/sharing-data' +next: + text: Authorization + link: '/boring-stack/authorization' +editLink: true +--- + +# {{ $frontmatter.title }} {#authentication} + +Authentication is the process of verifying the identity of a user, typically through credentials like a username and password. For example, logging into a GitHub account requires authentication. + +The Boring JavaScript Stack manages its own authentication. + +By default, the Boring JavaScript Stack offers you two mechanisms for authentication: + +1. Email and Password authentication +2. Provider authentication + +## Email and password authentication + +When a user wishes to sign up for an account, they are asked for their email address. The Boring Stack will send them an email with a link to verify their email. The user can click the link to verify their email address. + +The password is stored using the bcrypt algorithm and handled by the password helper from [Sails organics](https://github.com/sailshq/sails-hook-organics). + +## Provider authentication + +Using [Sails Wish](/wish), The Boring Stack supports third-party authentication allowing you to easily add SSO(Single Sign On) to your application. Out of the box The Boring Stack supports [OAuth with Google](/wish/google). You can easily setup [OAuth with GitHub](/wish/github) as well. diff --git a/docs/boring-stack/authorization.md b/docs/boring-stack/authorization.md new file mode 100644 index 0000000..6f52986 --- /dev/null +++ b/docs/boring-stack/authorization.md @@ -0,0 +1,47 @@ +--- +title: Authorization +titleTemplate: The Boring JavaScript Stack 🥱 +description: Authorization in The Boring JavaScript Stack +prev: + text: Authentication + link: '/boring-stack/authentication' +next: + text: Database + link: '/boring-stack/database' +editLink: true +--- + +# Authorization + +Authorization is the process of granting or denying access to specific resources or actions based on a user's authenticated identity. + +### Example Use Cases + +- **Admin access control:** Authorizing certain users to access and manage administrative functionalities. +- **Content permissions:** Granting or denying users access to specific content or features based on their roles. +- **Secure transactions:** Allowing authorized users to perform secure transactions or financial operations. + +Authorization within The Boring JavaScript Stack is orchestrated server-side through [Sails Policies](https://sailsjs.com/documentation/concepts/policies). These policies act as a shield, safeguarding your actions against unauthorized access. + +A common scenario involves permitting a user to access your dashboard exclusively when authenticated. To implement this, you can establish a `api/policies/is-authenticated.js` policy and then configure the actions you wish the policy to safeguard in `config/policies.js`: + +::: code-group + +```js [api/policies/is-authenticated.js] +module.exports = async function (req, res, proceed) { + if (req.session.userId) return proceed() + return res.redirect('/login') +} +``` + +```js [config/policies.js] +module.exports.policies = { + 'dashboard/*': 'is-authenticated' +} +``` + +::: + +::: info +Learn more about using [policies](https://sailsjs.com/documentation/concepts/policies) for authorization on the Sails docs. +::: diff --git a/docs/boring-stack/database.md b/docs/boring-stack/database.md new file mode 100644 index 0000000..ee0e3c8 --- /dev/null +++ b/docs/boring-stack/database.md @@ -0,0 +1,97 @@ +--- +title: Database +titleTemplate: The Boring JavaScript Stack 🥱 +description: Database in The Boring JavaScript Stack +prev: + text: Authorization + link: '/boring-stack/authorization' +next: + text: Email + link: '/boring-stack/email' +editLink: true +--- + +# Database + +A database is a structured collection of data organized for efficient retrieval and management. In web development, databases store and manage information essential for applications, such as user data, content, and settings. + +### Example use cases + +- **User data storage:** Storing and retrieving user profiles, preferences, and account information. +- **Content management:** Managing articles, posts, or any content within an application. +- **Configuration settings:** Storing and managing application settings and configurations. + +## Sails Disk + +During development, The Boring JavaScript Stack utilizes the [Sails Disk](https://sailsjs.com/documentation/concepts/extending-sails/adapters/available-adapters#sails-disk) adapter for Waterline, allowing you to kickstart your app without worrying about setting up a database. + +::: info +Learn more about [Sails Disk](https://sailsjs.com/documentation/concepts/extending-sails/adapters/available-adapters#?sailsdisk) on the Sails docs. +::: + +## Setting up a database + +To set up a database, you can choose the adapter for your chosen database and follow the setup steps. + +## PostgreSQL + +::: code-group + +```sh [terminal] +npm i sails-postgresql --save +``` + +```js [config/datastores.js] +module.exports.datastores = { + default: { + adapter: 'sails-postgresql', // [!code focus] + url: 'postgresql://user:password@host:port/database' // [!code focus] + } +} +``` + +::: + +## MySQL + +::: code-group + +```sh [terminal] +npm i sails-mysql --save +``` + +```js [config/datastores.js] +module.exports.datastores = { + default: { + adapter: 'sails-mysql', // [!code focus] + url: 'mysql://user:password@host:port/database' // [!code focus] + } +} +``` + +::: + +## MongoDB + +::: code-group + +```sh [terminal] +npm i sails-mongo --save +``` + +```js [config/datastores.js] +module.exports.datastores = { + default: { + adapter: 'sails-mongo', // [!code focus] + url: 'mongodb://user:password@host:port/database' // [!code focus] + } +} +``` + +::: + +## SQLite + +::: info +The SQLite adapter is under development. You can keep an eye on the [repo](https://github.com/sailscastshq/sails-sqlite). +::: diff --git a/docs/boring-stack/email.md b/docs/boring-stack/email.md new file mode 100644 index 0000000..2122cff --- /dev/null +++ b/docs/boring-stack/email.md @@ -0,0 +1,45 @@ +--- +title: Email +titleTemplate: The Boring JavaScript Stack 🥱 +description: Sending emails in The Boring JavaScript Stack +prev: + text: Database + link: '/boring-stack/database' +next: + text: Session + link: '/boring-stack/session' +editLink: true +--- + +# Email + +Sending transactional emails plays a crucial role in keeping users informed about specific actions or events. It involves delivering personalized and time-sensitive messages triggered by user interactions. + +### Example use cases + +- **User Registration Confirmation:** Sending an email to verify and confirm a user's registration. +- **Password Reset Requests:** Notifying users and providing a secure link to reset their passwords. +- **Order Confirmations:** Informing users about successful purchases with order details. + +Sending emails in The Boring JavaScript is powered by the [Sails Mail](/mail) hook. + +::: info +Learn all about [Sails Mail](/mail) in the Mail docs. +::: + +## Sending emails + +To send emails in The Boring JavaScript Stack, use the `sails.helpers.mail.send()` helper: + +```js +// controllers/user/signup.js +await sails.helpers.mail.send.with({ + subject: 'Verify your email', + template: 'email-verify-account', + to: unverifiedUser.email, + templateData: { + token: unverifiedUser.emailProofToken, + fullName: unverifiedUser.fullName + } +}) +``` diff --git a/docs/boring-stack/error-handling.md b/docs/boring-stack/error-handling.md new file mode 100644 index 0000000..9fac16d --- /dev/null +++ b/docs/boring-stack/error-handling.md @@ -0,0 +1,16 @@ +--- +title: Error handling +titleTemplate: The Boring JavaScript Stack 🥱 +description: Error handling in The Boring JavaScript Stack +prev: + text: Redirects + link: '/boring-stack/redirects' +next: + text: Sharing data + link: '/boring-stack/sharing-data' +editLink: true +--- + +# Error handling + +Coming soon :soon: diff --git a/docs/boring-stack/getting-started.md b/docs/boring-stack/getting-started.md index a8130ee..8e19023 100644 --- a/docs/boring-stack/getting-started.md +++ b/docs/boring-stack/getting-started.md @@ -1,7 +1,71 @@ --- -title: Getting Started, -description: To install and setup captain-vane run npm i --save-dev captain-vane captain-vane-generator, +title: Getting started +titleTemplate: The Boring JavaScript Stack 🥱 +description: The Boring JavaScript Stack let's you build full-stack JavaScript apps with Vue, React, or Svelte. +prev: + text: What's in the stack? + link: /boring-stack/whats-in-the-stack +next: + text: Routing + link: /boring-stack/routing editLink: true --- -## Coming soon 🥱 +# Getting started + +Simply run the below command in your terminal to get started: + +::: code-group + +```sh [Vue] +npx create-sails project-name --vue +``` + +```sh [React] +npx create-sails project-name --react +``` + +```sh [Svelte] +npx create-sails project-name --svelte +``` + +::: + +::: info +Make sure to replace `project-name` with the name of your project. +::: + +Then `cd` into your project and run `npm i`: + +```sh +cd project-name && npm i +``` + +## Start your app + +To start you app simply run: + +```sh +npm run dev +``` + +::: info sails lift +You can also run your app with `npx sails l`. +::: + +## What's next? + +For next steps, you have two options: + +1. Open your project in your code editor and explore. +2. Begin by learning the basics, such as [routing](/boring-stack/routing) and [navigation](/boring-stack/navigation). + +::: info Sailboat VS Code extension +Install the [Sailboat extension](https://marketplace.visualstudio.com/items?itemName=dominuskelvin.sailboat) which provides tooling for Sails. +::: + +## Star the repo :star: + +::: tip Star The Boring JavaScript Stack repo on GitHub :star: +If The Boring JavaScript Stack speaks to you, show it some love with [a star on GitHub](https://github.com/sailscastshq/boring-stack). +::: diff --git a/docs/boring-stack/navigation.md b/docs/boring-stack/navigation.md new file mode 100644 index 0000000..b00f876 --- /dev/null +++ b/docs/boring-stack/navigation.md @@ -0,0 +1,58 @@ +--- +title: Navigation +titleTemplate: The Boring JavaScript Stack 🥱 +description: To navigate in your SPA use the provided Links component for your UI framework. +prev: + text: 'Routing' + link: '/boring-stack/routing' +next: + text: 'Redirects' + link: '/boring-stack/redirects' +editLink: true +--- + +# Navigation + +## Standard navigation + +To navigate in pages/views that are not controlled by Inertia, use the standard ``. Not surprisingly, it works really well. :wink: + +## Inertia navigation + +To navigate in pages, use the Inertia `` component. The `` component is a light wrapper around a standard anchor `` tag that intercepts click events and prevent full page reloads. + +::: info +Learn more about [how Inertia provide an SPA experience](https://inertiajs.com/how-it-works) in the Inertia docs. +::: + +## Creating links + +To create an Inertia link, use the Inertia `` component. Any attributes you provide to this component will be proxied to the underlying HTML tag. + +::: code-group + +```vue [Vue] + + + +``` + +```jsx [React] +import { Link } from '@inertiajs/react' + +function Nav() { + return Home // [!code focus] +} +``` + +```svelte [Svelte] +import { inertia, Link } from '@inertiajs/svelte' + +Home + +Home +``` + +::: diff --git a/docs/boring-stack/redirects.md b/docs/boring-stack/redirects.md new file mode 100644 index 0000000..af0daa9 --- /dev/null +++ b/docs/boring-stack/redirects.md @@ -0,0 +1,78 @@ +--- +title: Redirects +titleTemplate: The Boring JavaScript Stack 🥱 +description: Redirecting in The Boring JavaScript Stack +prev: + text: Navigation + link: '/boring-stack/navigation' +next: + text: Error handling + link: '/boring-stack/error-handling' +editLink: true +--- + +# {{ $frontmatter.title }} {#redirects} + +## Route target redirect + +You can set up one route to redirect to another route within your app or even to another absolute URL in your `config/routes.js`. + +```js +module.exports.routes = { + '/chat': '/community', // [!code focus] + 'GET /docs': 'https://docs.sailscasts.com' // [!code focus] +} +``` + +::: info +Learn more about [Route target redirect](https://sailsjs.com/documentation/concepts/routes/custom-routes#?redirect-target-syntax) on the Sails docs. +::: + +## Exit signal redirect + +You can also set an exit to signal a redirect in your action. + +```js +module.exports = { + exits: { + // [!code focus] + success: { + // [!code focus] + responseType: 'redirect' // [!code focus] + } // [!code focus] + }, // [!code focus] + fn: async function (inputs) { + return '/' // [!code focus] + } +} +``` + +Notice we set the `responseType` to `redirect` and then we can return a URL string. + +::: info +Learn more about [Actions and Controllers](https://sailsjs.com/documentation/concepts/actions-and-controllers) on the Sails docs. +::: + +## 303 response code for SPAs + +When redirecting after a `PUT`, `PATCH`, or `DELETE` request from your SPA, you must use a `303` response code, otherwise the subsequent request will not be treated as a `GET` request. A `303` redirect is very similar to a `302` redirect; however, the follow-up request is explicitly changed to a `GET` request. + +The Boring Stack provides you with a helper method to do that in your controller actions: + +```js +return sails.inertia.location(url) +``` + +::: info +Learn more about [303 response code](https://inertiajs.com/redirects#303-response-code) on the Inertia docs. +::: + +## External redirects + +Sometimes it's necessary to redirect to an external website, or even another page in your app that's not an SPA. This can be accomplished using a server-side initiated `window.location` visit via the `sails.inertia.location()` method. + +```js +return sails.inertia.location(url) +``` + +The `sails.inertia.location(url)` method will generate a `409` Conflict response if the redirect request is coming from a `POST` or `GET` method and include the destination URL in the `X-Inertia-Location` header. When this response is received client-side, Inertia will automatically perform a `window.location = url` visit. diff --git a/docs/boring-stack/render.md b/docs/boring-stack/render.md new file mode 100644 index 0000000..b418e4d --- /dev/null +++ b/docs/boring-stack/render.md @@ -0,0 +1,119 @@ +--- +title: Deploy on Render +titleTemplate: The Boring JavaScript Stack 🥱 +description: Deploy your app on Render +prev: + text: 'Session' + link: '/boring-stack/session' +next: false +editLink: true +--- + +# Deploy on Render + +Let's deploy your app on [Render](https://render.com) :rocket: + +## GitHub Repo + +Push your app to a repo on GitHub. + +## Create database + +Create the database you want to use for production on Render and take note of the connection url. +::: info Database creation guides +See guides for [MySQL](https://docs.render.com/deploy-mysql), [PostgreSQL](https://docs.render.com/databases), and, [MongoDB](https://docs.render.com/deploy-mongodb) on the Render docs. +::: + +## Create Redis instance + +Create the production Redis instance and take note of the connection url. +::: info Redis instance guide +See the [guide to create a Redis instance](https://docs.render.com/redis#creating-a-redis-instance) on the Render docs. +::: + +## Set up database + +Depending on the database you want to use for production, [set up that adapter](/boring-stack/database) in `config/environment/production.js` +::: code-group + +```js [PostgreSQL] +module.exports = { + datastores: { + default: { + adapter: 'sails-postgresql', + url: process.env.DATABASE_URL + } + } +} +``` + +```js [MySQL] +module.exports = { + datastores: { + default: { + adapter: 'sails-mysql', + url: process.env.DATABASE_URL + } + } +} +``` + +```js [MongoDB] +module.exports = { + datastores: { + default: { + adapter: 'sails-mongo', + url: process.env.DATABASE_URL + } + } +} +``` + +::: + +::: warning +Don't forget to install the adapter if you haven't already. See the [database](/boring-stack/database) docs for more info. +::: + +## Set up Redis + +::: info +[Create a new Redis instance](https://docs.render.com/redis) on Render by following the Render docs. +::: +Set up the Redis adapter in `config/environment/production.js` + +```js +module.exports = { + session: { + secret: process.env.REDIS_SECRET + adapter: '@sailshq/connect-redis', + url: process.env.REDIS_URL + } +} +``` + +## Create a web service + +Create a new Node.js [Web Service](https://docs.render.com/web-services) on Render, and give Render permission to access the repo of your app. + +Use the following values during creation: + +- **Runtime**: `Node` +- **Build command**: `npm i` +- **Start command**: `npm start` + +## Set environment variables + +Add the following evironment variables to your web service: + +- `DATABASE_URL`: This should point to the connection string of the database you created. +- `REDIS_URL`: This should point to the connection string to the Redis instance you created. +- `SESSION_SECRET`: A unique production session secret to override the one in `config/session.js`. + +That’s it! Your app will be live on your Render URL as soon as the build finishes :tada: + +## Celebrate with a :star: + +::: tip Star The Boring JavaScript Stack repo on GitHub :star: +Let's celebrate deploying your app on Render by giving **The Boring JavaScript Stack** [a star on GitHub](https://github.com/sailscastshq/boring-stack). +::: diff --git a/docs/boring-stack/routing.md b/docs/boring-stack/routing.md new file mode 100644 index 0000000..6657d61 --- /dev/null +++ b/docs/boring-stack/routing.md @@ -0,0 +1,47 @@ +--- +title: Routing +titleTemplate: The Boring JavaScript Stack 🥱 +description: In The Boring JavaScript Stack, all of your application's routes are defined server-side. This means that you don't need Vue Router or React Router. +prev: + text: 'Getting Started' + link: '/boring-stack/getting-started' +next: + text: Navigation + link: '/boring-stack/navigation' +editLink: true +--- + +# Routing + +## Defining routes + +In The Boring JavaScript Stack, all of your application's routes are defined server-side. This means that you don't need Vue Router or React Router. + +Instead, you can simply define [Sails routes](https://sailsjs.com/documentation/concepts/routes) and return an Inertia responses for SPA or return a server-side view for server-side rendering from those routes. + +For example let's say we want to create a `/users` route, we can define the route in `config/routes.js`: + +```js +module.exports.routes = { + 'GET /users': 'user/view-users' // [!code focus] +} +``` + +The above route definition means that when a user requests the `/users` page of your app, the `view-users` action of the `user` controller will handle that request. Let's implement `user/view-users`. + +::: tip +Run `npx sails generate action user/view-users` to scaffold the action. +::: + +```js +module.exports = { + inputs: {}, + exits: { + success: {} + }, + fn: async function (inputs) { + const users = await User.find() + return sails.inertia.render('users/index', { users }) // [!code focus] + } +} +``` diff --git a/docs/boring-stack/session.md b/docs/boring-stack/session.md new file mode 100644 index 0000000..d1ceeea --- /dev/null +++ b/docs/boring-stack/session.md @@ -0,0 +1,81 @@ +--- +title: Session +titleTemplate: The Boring JavaScript Stack 🥱 +description: The Boring JavaScript Stack ships with Session based authentication +prev: + text: 'Email' + link: '/boring-stack/email' +next: + text: 'Deploy on Render' + link: '/boring-stack/render' +editLink: true +--- + +# Session + +A session is a mechanism that enables websites to store and retrieve user-specific information temporarily. It allows for personalized and stateful interactions during a user's visit. + +### Example use cases + +- **User authentication:** Keeping track of whether a user is logged in or not. +- **Shopping cart persistence:** Retaining items in a user's shopping cart across different pages. +- **Personalized preferences:** Storing and recalling user-specific settings or preferences. + +## In memory session store + +**The Boring JavaScript Stack** ships with the tried and tested session-based authentication. In development you can rely on the in-memory Sails session store that works out of the box. + +Because the default session store is in memory, when you close the Sails server, the current session store disappears. + +::: info +Learn more about [how sessions work](https://sailsjs.com/documentation/concepts/sessions) on the Sails docs. +::: + +## Persistent session store + +Redis is a popular choice to use as a persistent session store. To set it up, install `@sailshq/connect-redis` and then update `config/session.js`: + +::: code-group + +```sh [terminal] +npm i @sailshq/connect-redis --save +``` + +```js [config/session.js] +module.exports.session = { + adapter: '@sailshq/connect-redis', + url: 'redis://localhost:6379' +} +``` + +::: + +## Accessing the session store + +In **The Boring JavaScript Stack**, the session store is accessed in your actions via `this.req.session`. This provides a convenient way to interact with user session data within your application. Below is an example of logging in a user: + +```js +module.exports = { + fn: async function ({ email, password, rememberMe }) { + const user = await User.findOne({ + email: email.toLowerCase() + }) + + if (!user) { + throw 'badCombo' + } + + await sails.helpers.passwords + .checkPassword(password, user.password) + .intercept('incorrect', 'badCombo') + + if (rememberMe) { + this.req.session.cookie.maxAge = + sails.config.custom.rememberMeCookieMaxAge + } + + this.req.session.userId = user.id + return '/' + } +} +``` diff --git a/docs/boring-stack/sharing-data.md b/docs/boring-stack/sharing-data.md new file mode 100644 index 0000000..7f590a2 --- /dev/null +++ b/docs/boring-stack/sharing-data.md @@ -0,0 +1,60 @@ +--- +title: Sharing data +titleTemplate: The Boring JavaScript Stack 🥱 +description: Sharing data in The Boring JavaScript Stack +prev: + text: Error handling + link: '/boring-stack/error-handling' +next: + text: Authentication + link: '/boring-stack/authentication' +editLink: true +--- + +# Sharing data + +If you have data that you want to be provided as prop to your SPA (a common use-case is informationa about the authenticated user) you can use the `sails.inertia.share` method. + +You can do this in `api/hooks/custom/index.js`. + +## Example + +Here is an example of sharing the logged in user data: + +```js +module.exports = function defineCustomHook(sails) { + return { + /** + * Runs when this Sails app loads/lifts. + */ + initialize: async function () { + sails.log.info('Initializing custom hook (`custom`)') + }, + routes: { + before: { + 'GET /': { + skipAssets: true, + fn: async function (req, res, next) { + if (req.session.userId) { + const loggedInUser = await User.findOne({ + id: req.session.userId + }) + if (!loggedInUser) { + delete req.session.userId + return res.redirect('/login') + } + sails.inertia.share('loggedInUser', loggedInUser) // [!code focus] + return next() + } + return next() + } + } + } + } + } +} +``` + +::: info +Learn more about [sharing data](https://inertiajs.com/shared-data) on the Inertia docs. +::: diff --git a/docs/boring-stack/type-checking-js-files.md b/docs/boring-stack/type-checking-js-files.md new file mode 100644 index 0000000..4ba65e2 --- /dev/null +++ b/docs/boring-stack/type-checking-js-files.md @@ -0,0 +1,27 @@ +--- +title: Type checking JS files +titleTemplate: The Boring JavaScript 🥱 +description: Configuration on type checking in JS files +editLink: true +--- + +# Type checking JS files + +The Boring JavaScript Stack templates ships with a `jsconfig.json` file with configs that allows TypeScript's compiler in editors like VS Code to type check your JS files. + +While this is good, you will need to manually maintain a `types/index.d.ts` file so TypeScript don't complain too much. + +## Disabling type checking + +You can disable type-checking if its too much of an annoyance and you prefer just JavaScript by setting `checkJs` and `allowJs` to `false`: + +```json +{ + "compilerOptions": { + "allowJs": true, // [!code --] + "allowJs": false, // [!code ++] + "checkJs": true, // [!code --] + "checkJs": false // [!code ++] + } +} +``` diff --git a/docs/boring-stack/whats-in-the-stack.md b/docs/boring-stack/whats-in-the-stack.md new file mode 100644 index 0000000..aa007a1 --- /dev/null +++ b/docs/boring-stack/whats-in-the-stack.md @@ -0,0 +1,47 @@ +--- +title: What's in the stack? +titleTemplate: The Boring JavaScript Stack 🥱 +description: The Boring JavaScript comes with Sails, Inertia, Tailwind CSS, and Vue, React, or Svelte. It's about proven technologies prioritizing stability and efficiency, letting you focus on solving real web development problems without the noise of constant updates. +prev: + text: 'Who is it for?' + link: '/boring-stack/who-is-it-for' +next: + text: Getting started + link: '/boring-stack/getting-started' +editLink: true +--- + +# What's in The Boring JavaScript Stack? + +Alright, let's peel back the layers and take a look at what makes up **The Boring JavaScript Stack**. + +## Vue, React, or Svelte + +Whether you prefer the simplicity of [Vue](https://vuejs.org/), the flexibility of [React](https://reactjs.org/), or the efficiency of [Svelte](https://svelte.dev/), **The Boring JavaScript Stack** accommodates your choice. With The Boring JavaScript Stack, the UI of your app are simply the components of your chosen UI framework. + +So if you enjoy writing React's JSX, you'd love The Boring JavaScript Stack as that's the only thing you have to know from React - writing components. Same thing with Vue and Svelte. + +## Tailwind CSS + +[Tailwind CSS](https://tailwindcss.com/), the utility-first CSS framework makes styling feels like cheating. It that the styling backbone of this stack. + +Since The Boring JavaScript Stack is about being pragmatic, what's better than Tailwind CSS in practicality, efficiency, and ensuring your styles are predictable and easy to manage? + +## Inertia + +[Inertia](https://inertiajs.com/) allows you to build modern single-page apps without the need for a full-blown API. It keeps things simple and straightforward, emphasizing stability in your UI(frontend) development. + +## Sails + +At the core of this stack is [Sails](https://sailsjs.com/), a web framework that's been around the block and has proven itself. It's not trying to reinvent the wheel; instead, it focuses on providing a solid foundation for building scalable and maintainable web applications. + +Because we’re using Sails as the web framework, we can leverage a lot of its features including: + +- [Authentication](https://sailsjs.com/documentation/concepts/sessions#how-sessions-work-in-sails-advanced-): Sails has a robust support for session-based authentication. +- [Sails Wish](https://docs.sailscasts.com/wish/): Easily setup OAuth flows with providers like [GitHub](https://docs.sailscasts.com/wish/github) or [Google](https://docs.sailscasts.com/wish/google) in your Sails applications. +- [Authorization](https://sailsjs.com/documentation/concepts/policies): Sails has policies which are versatile tools for authorization and access control: they let you execute some logic before an action is run in order to determine whether or not to continue processing the request. +- [Waterline ORM](https://sailsjs.com/documentation/concepts/models-and-orm): Sails comes installed with a powerful [ORM/ODM](http://stackoverflow.com/questions/12261866/what-is-the-difference-between-an-orm-and-an-odm) called Waterline, a datastore-agnostic tool that dramatically simplifies interaction with one or more databases. +- [WebSocket support](https://sailsjs.com/documentation/concepts/realtime): Sails apps are capable of full-duplex, realtime communication between the client and server. +- [File uploads](https://sailsjs.com/documentation/concepts/file-uploads): [Skipper](https://github.com/sailshq/skipper) makes it easy to implement streaming file uploads to disk, S3, or any supported file upload adapters. +- [Shell scripts](https://sailsjs.com/documentation/concepts/shell-scripts): Sails lets you run JavaScript functions as shell scripts. This can be useful for running scheduled jobs (cron, Heroku scheduler), worker processes, and any other custom, one-off scripts that need access to your Sails app's models, configuration, and helpers. +- [Sails Mail](https://docs.sailscasts.com/mail/): Sails Mail provides an amazing and elegant API for sending emails. diff --git a/docs/boring-stack/who-is-it-for.md b/docs/boring-stack/who-is-it-for.md new file mode 100644 index 0000000..1889693 --- /dev/null +++ b/docs/boring-stack/who-is-it-for.md @@ -0,0 +1,46 @@ +--- +title: Who is it for? +titleTemplate: The Boring JavaScript Stack 🥱 +description: Wondering who vibes with The Boring JavaScript Stack? If you're all about practicality over trends, a business owner aiming for consistent services, or a team lead striving for efficiency – this stack is your jam. It's for startups with a long-term vision and devs craving problem-solving excitement. +prev: + text: Why the name + link: '/boring-stack/why-the-name' +next: + text: "What's in the stack?" + link: '/boring-stack/whats-in-the-stack' +editLink: true +--- + +# Who is The Boring JavaScript Stack for? + +So, you're probably wondering, "Who would benefit from embracing **The Boring JavaScript Stack**?" Well, let me break it down for you. + +## Pragmatic Developers + +If you're a developer who values practicality over chasing the latest shiny tool in the JavaScript playground, this stack is for you. **The Boring JavaScript Stack** is tailored for those who understand the importance of stability, reliability, and predictability in their tech choices. + +## Business Owners and Entrepreneurs + +Running a business comes with its own set of challenges. For those focused on solving real-world problems through web software, a "boring" tech stack can be a game-changer. + +If you're more interested in delivering consistent services to your users than constantly adapting to ever-changing technologies, this stack aligns perfectly with your business mindset. + +## Team Leads and Managers + +Efficiency and collaboration are key components of a successful development team. If you're leading a group of talented individuals, a "boring" tech stack facilitates smoother onboarding, reduced maintenance overhead, and a shared understanding among team members. + +It allows you to focus on delivering value to users rather than grappling with the complexities of bleeding-edge technologies. + +## Startups with a Long-Term Vision + +Startups often find themselves in a whirlwind of choices, trying to find the perfect tech stack that aligns with their vision. **The Boring JavaScript Stack** is particularly well-suited for startups with a long-term perspective. It provides a solid foundation, enabling you to concentrate on solving exciting problems and building a sustainable business. + +## Developers Who Crave Problem-Solving Excitement + +Yes, you read that right! If you're a developer seeking excitement, look no further than the problems you're solving, not the tools you're using. + +**The Boring JavaScript Stack** allows you to let the tools fade into the background, giving you the freedom to dive deep into the exciting challenges of web development without constantly being distracted by the latest tech trends. + +In essence, this stack is for those who understand that the real excitement in web development comes from creating solutions that make a difference. + +If you're tired of the constant rat race in the JavaScript ecosystem and want to focus on building amazing things with dependable technologies, then **The Boring JavaScript Stack** is your ticket to a more grounded and purposeful development journey. diff --git a/docs/boring-stack/why-the-name.md b/docs/boring-stack/why-the-name.md new file mode 100644 index 0000000..e04b735 --- /dev/null +++ b/docs/boring-stack/why-the-name.md @@ -0,0 +1,85 @@ +--- +title: Why the name? +titleTemplate: The Boring JavaScript Stack 🥱 +description: Discover the philosophy behind The Boring JavaScript Stack. It's a nod to stability, a rebellion against chasing trends. Embrace reliability for efficient web development without constant distractions. +next: + text: Who is it for + link: '/boring-stack/who-is-it-for' +editLink: true +--- + +# Why the name? + +The JavaScript ecosystem is so exciting - we are always coming up with newer ways to build web software. + +I don't know about you, but one of the reasons why I opted to base my career in web development on JavaScript was to build things quickly and easily. + +But with the constant state of chasing the next trend or reinventing the wheel, or in most cases ignoring that the wheel ever existed, we've been busy glorifying our hammers ⚒️ instead of building amazing things with them. + +## Boring technology + +We don't build web software in a vacuum; we do it to solve problems in our workplace, create an MVP for that killer idea, and so on. + +There are so many exciting problems to be solved with web software that it begs the question: Why are we wasting time and resources on what to build with? + +There are amazing technologies that have been tried and tested, which you can depend on. + +There is a school of thought that calls tried, tested, and stable technologies "boring tech," and **The Boring JavaScript Stack** is a tribute to that school of thought. It is also a contrarian movement against the trend in the JS ecosystem of chasing the shiny. + +With **The Boring JavaScript Stack**, you can get off the rat race in the JavaScript ecosystem and move fast by building with stable and boring technologies. + +## Boring is good + +Someone once expressed concerns with the name - **The Boring JavaScript Stack**. Their concern is that "...many will still be scared of the name." + +The fact that many people get scared by the name actually proves my point about glorifying the hammer instead of the building. It seems like the focus is on the wrong things. + +We've got to stop getting excited about tools and start getting excited about the problems we are solving with them. + +Boring technologies are... + +- stable +- tried +- tested +- stable(trust me, it's worth saying again.) +- predictable + +## Boring is good for business + +I'm pretty sure that when you solve problems via web software in your business, you are not in the business of burning through tools to build your solutions with. + +Rapidly evolving technologies can be more of a hindrance than a help. Instead of propelling your business forward, they can become stumbling blocks, impeding progress and diverting attention from what truly matters – delivering the services that your users depend on you for. + +In the realm of business, the reliability and steadiness of a "boring" tech stack can be a secret weapon, allowing you to stay focused on your core objectives and ensuring the sustained success of your venture. + +## Boring is good for teams + +Because your tech stack is boring, onboarding new teammates becomes easy because they can quickly get started. The technologies in the stack are stable, allowing them to hit the ground running. + +In addition to the ease of onboarding, a "boring" tech stack often translates to reduced maintenance overhead. Stability and predictability in technology choices mean fewer surprises and less time spent troubleshooting unexpected issues. + +This allows the team to focus on delivering value to users rather than constantly grappling with the latest trendy tools or dealing with the complexities of bleeding-edge technologies. + +Moreover, a standardized and well-established tech stack fosters collaboration and knowledge sharing within the team. Team members can easily support each other, as they share a common understanding of the tools and processes in place. + +This uniformity also facilitates the creation of best practices, enabling the team to optimize their workflows and maintain a cohesive and efficient development environment. In the long run, a "boring" tech stack can contribute to a more sustainable and productive team dynamic. + +## Boring is good for teams + +Because your tech stack is boring, onboarding new teammates becomes easy because they can quickly get started. The technologies in the stack are stable, allowing them to hit the ground running. + +In addition to the ease of onboarding, a "boring" tech stack often translates to reduced maintenance overhead. Stability and predictability in technology choices mean fewer surprises and less time spent troubleshooting unexpected issues. + +This allows the team to focus on delivering value to users rather than constantly grappling with the latest trendy tools or dealing with the complexities of bleeding-edge technologies. + +Moreover, a standardized and well-established tech stack fosters collaboration and knowledge sharing within the team. Team members can easily support each other, as they share a common understanding of the tools and processes in place. + +This uniformity also facilitates the creation of best practices, enabling the team to optimize their workflows and maintain a cohesive and efficient development environment. In the long run, a "boring" tech stack can contribute to a more sustainable and productive team dynamic. + +## Solve exciting problems + +Want excitements? Who doesn't 😁! Don't look to your tools for that excitement, look to the problems you are solving. + +For example, [Lemon Squeezy](https://lemonsqueezy.com/) using a flavor of The Boring JavaScript Stack - Laravel is the web framework of choice, not Sails. They are busy solving the exciting problem of enabling creators to receive payments on the internet. I am also building [Hagfish](https://hagfish.io/) and [Sailscasts](https://sailscasts.com/) on The Boring JavaScript Stack! + +In fact, the more boring your stack is, the quicker you can let the tools fade into the background while you zoom in on the problems you are solving. Your tools are supposed to enable you to be awesome, not for them to be awesome in your eyes. diff --git a/docs/images/boring-stack/logo.png b/docs/images/boring-stack/logo.png new file mode 100644 index 0000000..53a9805 Binary files /dev/null and b/docs/images/boring-stack/logo.png differ diff --git a/package.json b/package.json index 91664fd..1b669ac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sailscasts-docs", - "version": "1.1.1", + "version": "1.2.0", "private": true, "description": "The official docs hub for Sailscasts", "scripts": {