1678189080
Dans ce didacticiel, vous découvrirez Astro, un framework open source pour générer des applications Web - le framework Web tout-en-un. Ce didacticiel comprend des images et du code de guide utiles. Astro est un framework Web axé sur le contenu et rendu par service pour créer des sites Web rapides et légers. Il peut également remplacer Gatsby comme Next.js.
Le développement Web, comme la plupart des technologies, évolue par vagues et par cycles. Les sites Web statiques étaient tout ce que nous avions au début. Mais très vite, les développeurs ont hacké ensemble les premiers sites générés par le serveur grâce à Perl et PHP. C'était l'avancée qui allait éventuellement lancer des frameworks comme Laravel, Django ou Rails.
Mobile devices would come to change how people consume the web. So long server-generated websites, hello client-rendered applications. The next wave brought frameworks that could give users a more app-like experience — without reloads — like React or AngularJS.
But while single-page applications did provide a smoother experience, they have their drawbacks. Namely, longer page loads caused by all the extra JavaScript that has to be parsed and executed. Not to mention all the work it took to optimize for search engines.
Astro is a prime example of the current wave that we have been in since Next.js, taking us full circle: a web framework that combines server and client rendering to get the best of both worlds.
Astro est un framework open source permettant de générer des applications Web en plus des frameworks d'interface utilisateur populaires tels que React , Preact , Vue ou Svelte . Une page Astro est composée de plusieurs composants indépendants. Pour améliorer les temps de chargement, Astro supprime tous les pages JavaScript et prérendues du serveur, à moins que les développeurs ne marquent un composant comme interactif, auquel cas Astro enverra la quantité minimale de JavaScript requise pour l'interactivité.
Astro favorise la génération de sites statiques et rendus par le serveur sans JavaScript dans le navigateur. Les développeurs peuvent opter pour le rendu côté client pour des itinéraires ou des parties de page donnés.
Thanks to this strategy, Astro pages load quickly, as no JavaScript needs to execute for the first render. In a process called hydration, Astro will “pour” JavaScript into components to make them dynamic.
Astro stands out from the other web frameworks in many ways:
To get started with Astro, install Node version 16.12.0 or higher and run the following command. Follow the on-screen wizard and choose to create an empty project when prompted:
$ npm create astro@latest
astro v1.9.1 Launch sequence initiated.
✔ Where would you like to create your new project? … awesome-website
✔ How would you like to setup your new project? › an empty project
✔ Template copied!
✔ Would you like to install npm dependencies? (recommended) … yes
✔ Packages installed!
✔ Would you like to initialize a new git repository? (optional) … yes
✔ Git repository created!
✔ How would you like to setup TypeScript? › Relaxed
✔ TypeScript settings applied!
next Liftoff confirmed. Explore your project!
Next, you can start the website in developer mode by entering the directory of the project you just created and running: “npm run dev” and visiting http://localhost:3000.
The interesting stuff in Astro happens inside the src folder. Checking what’s there, we see a single directory called pages with an index.astro file.
Astro pages are a mix of HTML, Javascript, or TypeScript. This is the default index.astro:
---
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Astro</title>
</head>
<body>
<h1>Astro</h1>
</body>
</html>
You may have noticed that Astro files start with fences delineated with ---. Whatever code we put inside these fences is executed on the server and prerendered before serving the page.
Below the frontmatter, we find the content for this route, an augmented HTML form that allows for variables. We can, for example, define a variable in the frontmatter and use it in HTML like this:
---
// src/pages/index.astro
const title = "Astro";
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>{title}</title>
</head>
<body>
<h1>{title}</h1>
</body>
</html>
Astro utilise un routage basé sur les fichiers , de sorte que chaque fichier du pagesdossier est mappé sur un itinéraire du site Web. Par exemple, si nous créons un fichier appelé greetings.astro, nous devrions voir son contenu dans http://localhost:3000/greetings.
---
const greeting = "Hello, world!";
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Astro</title>
</head>
<body>
<h1>{greeting}</h1>
</body>
</html>
En plus des .astrofichiers, Astro peut analyser les fichiers Markdown, MDX, JSX JavaScript et TypeScript. Par exemple, si nous voulons écrire un article de blog dans Markdown, nous créons un post.mdfichier sous le pagesdossier. La visite de l'itinéraire obligera Astro à le convertir en HTML à la volée :
---
title: 'Learning Astro'
pubDate: 2023-01-10
description: 'A post written in Markdown.'ma
author: 'Tommy'
---
# Learning Astro
This Markdown file should be rendered as HTML when I visit http://localhost:3000/post
Les composants Astro sont *.astrodes fichiers avec du code réutilisable et du HTML. Nous pouvons utiliser des composants pour écrire des éléments tels que des en-têtes, des pieds de page, des barres de navigation, des boutons et des formulaires - tout ce qui peut être exprimé en HTML peut constituer un composant.
Let’s create our first component in src/components/Header.astro:
---
// src/components/Header.astro
---
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator"
<title>Astro</title>
Once defined, we can import it to any page (or other components) and use it like this:
---
import Header from "../components/Header.astro";
---
<html lang="en">
<head>
<Header />
</head>
<body>
</body>
</html>
Astro components are no different from pages. Any code defined between fences is executed on the server. JavaScript is stripped out before sending the content to the browser.
Layouts are used to refine reusable UI structures. They are technically components, so the syntax stays the same.
Let’s replace the content of index.astro with a layout:
---
// src/pages/index.astro
import SiteLayout from "../layouts/SiteLayout.astro";
---
<SiteLayout></SiteLayout>
As you can see, layouts are stored in the src/layouts folder by convention.
Layouts, like components, can include other components. Here we have extracted the structure in index.astro and added a Footer component:
---
// src/layouts/SiteLayout.astro
import Header from "../components/Header.astro";
import Footer from "../components/Footer.astro";
---
<html lang="en">
<head>
<Header />
</head>
<body>
<Footer />
</body>
</html>
So far, our website has been completely static. In order to pass data between pages and components, we need to understand how props and slots work.
Components and layouts can define and accept props (short for properties) via the global Astro.props. Values passed through props are accessible to the component before rendering.
We can read props in our component like this:
---
// src/components/Header.astro
const { title } = Astro.props;
---
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator"
<title>{title}</title>
The value of title can be supplied when the component is called, which in the following example happens through the SiteLayout layout.
---
// src/layouts/SiteLayout.astro
import Header from "../components/Header.astro";
import Footer from "../components/Footer.astro";
---
<html lang="en">
<head>
<Header title = "Welcome my Astro Blog!" />
</head>
<body>
<Footer />
</body>
</html>
⚠️ Note that you need spaces surrounding the equal sign, i.e. title="Hello" is NOT correct. Instead, it should be: title = "Hello".
Slot elements create placeholders for content to be injected later. To see how it works, we can add a <slot /> element in src/layouts/SiteLayout.astro:
---
// src/layouts/SiteLayout.astro
import Header from "../components/Header.astro";
import Footer from "../components/Footer.astro";
---
<html lang="en">
<head>
<Header title = "Welcome my Astro Blog!" />
</head>
<body>
<slot />
<Footer />
</body>
</html>
Now the HTML inside <SiteLayout> is injected into the point where the slot is located.
---
// src/pages/index.astro
import SiteLayout from "../layouts/SiteLayout.astro";
---
<SiteLayout>
<p>This content is rendered in the slot</p>
</SiteLayout>
Nesting components, layouts, props, and slots give us the flexibility to create reusable UI files across the website.
Up to this point, we have not shipped any JavaScript to the user; everything is prerendered and served as pure HTML+CSS. How do we send make Astro send JavaScript to the browser? For that, we need to understand the islands architecture.
The island architecture pattern aims to reduce the amount of JavaScript needed browser-side. Less JavaScript means less data sent and less computational power required on the user’s device. An island is an autonomous component that bundles HTML, CSS, and — optionally — JavaScript. In the islands pattern, a page is made up of several independent islands.
The islands architecture allows combining static HTML, server-rendered content, and interactive client-rendered components on one page without conflicts.
Each island is prerendered, so there is no interactivity right after the page loads. Once the initial page is ready, the islands are converted into interactive content in a process called hydration. Hydration is a technique that converts static content delivered via static hosting or server-side rendering into a dynamic page by attaching event handlers to the HTML elements.
How hydration works. The first contentful paint happens right after all the HTML has been sent to the browser, which typically happens very quickly. The browser then requests and executes all the client-side JavaScript needed to make the page fully interactive.
An example showing how Astro implements islands is in order. Let’s first add a UI integration to the project. The following command installs @astrojs/preact and preact.
$ npx astro add preact
Let’s create a simple button to test the integration:
// src/components/MyButton.jsx
export default function MyButton() {
const clicked = () => { console.log('Hello!') };
return (
<div>
<button style={{ color: 'purple' }} onClick={clicked}>Click me</button>
</div>
)
}
As usual, Astro will try to strip away any JavaScript. So nothing would happen if we instantiated the component with <MyButton />. We need to tell Astro that we want this component treated as an island and hydrated accordingly by adding the template directive client:load:
---
import MyButton from "../components/MyButton.jsx";
---
<html lang="en">
<body>
<MyButton client:load />
</body>
</html>
Clicking the button should print “Hello!” in the browser console.
The client directive caused Astro to hydrate the component. There are five levels of hydration with different priorities:
Being a Node application, setting up an Astro build with CI/CD is very straightforward. We only need a couple of jobs.
A possible continuous integration pipeline for Astro.
The first job runs npm ci to populate node_modules. We use sem-version to select a current Node version.
checkout
sem-version node 19.4
npm ci
cache store
The second job runs npm run build and stores the built application (located in the dist folder) as a workflow artifact.
checkout
sem-version node 19.4
cache restore
npm run build
artifact push workflow dist/
Once the site is built, we can configure continuous deployment.
Depending on the nature of the web application, Astro can be deployed as a static site à la Hugo or Gatsby, in which case we only need something as simple as an S3 bucket or GitHub pages, or as a full-fledged server-side rendered (SSR) application, where we need JavaScript- or TypeScript-enabled endpoints.
Astro has built-in support for various popular deployment targets such as Netlify, Firebase, Vercel, and Deno. Some only support either SSR or static hosting, while others can do both.
Once we have chosen our deployment method, we can add a continuous deployment pipeline to automatically deploy the website on every change.
Here’s an example deployment pipeline that targets a Netlify static site.
The complete CI/CD workflow with continuous deployment to Netlify.
Pour référence, les commandes de travail sont les suivantes. Cela suppose que nous ayons déjà obtenu un jeton API et l'avons enregistré en tant que secret sur Semaphore avec les variables d'environnement NETLIFY_TOKEN et NETLIFY_SITE.
checkout
artifact pull workflow dist
npm install -g netlify-cli
netlify deploy --dir=dist --prod --auth $NETLIFY_TOKEN --site $NETLIFY_SITE
La popularité de ce projet a été tout simplement astronomique : au cours des cinq premiers mois depuis la sortie d'Astro 1.0, le projet a amassé plus de 25 000 étoiles sur GitHub. Le succès d'Astro n'est pas accidentel. L'équipe Astro a créé un framework Web qui offre une excellente ergonomie pour les développeurs et des sites Web à chargement rapide pour les utilisateurs, même s'ils sont sur des appareils à faible consommation ou des connexions lentes.
Merci d'avoir lu et bonne construction !
Source : https://semaphoreci.com
#astro
1678189080
Dans ce didacticiel, vous découvrirez Astro, un framework open source pour générer des applications Web - le framework Web tout-en-un. Ce didacticiel comprend des images et du code de guide utiles. Astro est un framework Web axé sur le contenu et rendu par service pour créer des sites Web rapides et légers. Il peut également remplacer Gatsby comme Next.js.
Le développement Web, comme la plupart des technologies, évolue par vagues et par cycles. Les sites Web statiques étaient tout ce que nous avions au début. Mais très vite, les développeurs ont hacké ensemble les premiers sites générés par le serveur grâce à Perl et PHP. C'était l'avancée qui allait éventuellement lancer des frameworks comme Laravel, Django ou Rails.
Mobile devices would come to change how people consume the web. So long server-generated websites, hello client-rendered applications. The next wave brought frameworks that could give users a more app-like experience — without reloads — like React or AngularJS.
But while single-page applications did provide a smoother experience, they have their drawbacks. Namely, longer page loads caused by all the extra JavaScript that has to be parsed and executed. Not to mention all the work it took to optimize for search engines.
Astro is a prime example of the current wave that we have been in since Next.js, taking us full circle: a web framework that combines server and client rendering to get the best of both worlds.
Astro est un framework open source permettant de générer des applications Web en plus des frameworks d'interface utilisateur populaires tels que React , Preact , Vue ou Svelte . Une page Astro est composée de plusieurs composants indépendants. Pour améliorer les temps de chargement, Astro supprime tous les pages JavaScript et prérendues du serveur, à moins que les développeurs ne marquent un composant comme interactif, auquel cas Astro enverra la quantité minimale de JavaScript requise pour l'interactivité.
Astro favorise la génération de sites statiques et rendus par le serveur sans JavaScript dans le navigateur. Les développeurs peuvent opter pour le rendu côté client pour des itinéraires ou des parties de page donnés.
Thanks to this strategy, Astro pages load quickly, as no JavaScript needs to execute for the first render. In a process called hydration, Astro will “pour” JavaScript into components to make them dynamic.
Astro stands out from the other web frameworks in many ways:
To get started with Astro, install Node version 16.12.0 or higher and run the following command. Follow the on-screen wizard and choose to create an empty project when prompted:
$ npm create astro@latest
astro v1.9.1 Launch sequence initiated.
✔ Where would you like to create your new project? … awesome-website
✔ How would you like to setup your new project? › an empty project
✔ Template copied!
✔ Would you like to install npm dependencies? (recommended) … yes
✔ Packages installed!
✔ Would you like to initialize a new git repository? (optional) … yes
✔ Git repository created!
✔ How would you like to setup TypeScript? › Relaxed
✔ TypeScript settings applied!
next Liftoff confirmed. Explore your project!
Next, you can start the website in developer mode by entering the directory of the project you just created and running: “npm run dev” and visiting http://localhost:3000.
The interesting stuff in Astro happens inside the src folder. Checking what’s there, we see a single directory called pages with an index.astro file.
Astro pages are a mix of HTML, Javascript, or TypeScript. This is the default index.astro:
---
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Astro</title>
</head>
<body>
<h1>Astro</h1>
</body>
</html>
You may have noticed that Astro files start with fences delineated with ---. Whatever code we put inside these fences is executed on the server and prerendered before serving the page.
Below the frontmatter, we find the content for this route, an augmented HTML form that allows for variables. We can, for example, define a variable in the frontmatter and use it in HTML like this:
---
// src/pages/index.astro
const title = "Astro";
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>{title}</title>
</head>
<body>
<h1>{title}</h1>
</body>
</html>
Astro utilise un routage basé sur les fichiers , de sorte que chaque fichier du pagesdossier est mappé sur un itinéraire du site Web. Par exemple, si nous créons un fichier appelé greetings.astro, nous devrions voir son contenu dans http://localhost:3000/greetings.
---
const greeting = "Hello, world!";
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Astro</title>
</head>
<body>
<h1>{greeting}</h1>
</body>
</html>
En plus des .astrofichiers, Astro peut analyser les fichiers Markdown, MDX, JSX JavaScript et TypeScript. Par exemple, si nous voulons écrire un article de blog dans Markdown, nous créons un post.mdfichier sous le pagesdossier. La visite de l'itinéraire obligera Astro à le convertir en HTML à la volée :
---
title: 'Learning Astro'
pubDate: 2023-01-10
description: 'A post written in Markdown.'ma
author: 'Tommy'
---
# Learning Astro
This Markdown file should be rendered as HTML when I visit http://localhost:3000/post
Les composants Astro sont *.astrodes fichiers avec du code réutilisable et du HTML. Nous pouvons utiliser des composants pour écrire des éléments tels que des en-têtes, des pieds de page, des barres de navigation, des boutons et des formulaires - tout ce qui peut être exprimé en HTML peut constituer un composant.
Let’s create our first component in src/components/Header.astro:
---
// src/components/Header.astro
---
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator"
<title>Astro</title>
Once defined, we can import it to any page (or other components) and use it like this:
---
import Header from "../components/Header.astro";
---
<html lang="en">
<head>
<Header />
</head>
<body>
</body>
</html>
Astro components are no different from pages. Any code defined between fences is executed on the server. JavaScript is stripped out before sending the content to the browser.
Layouts are used to refine reusable UI structures. They are technically components, so the syntax stays the same.
Let’s replace the content of index.astro with a layout:
---
// src/pages/index.astro
import SiteLayout from "../layouts/SiteLayout.astro";
---
<SiteLayout></SiteLayout>
As you can see, layouts are stored in the src/layouts folder by convention.
Layouts, like components, can include other components. Here we have extracted the structure in index.astro and added a Footer component:
---
// src/layouts/SiteLayout.astro
import Header from "../components/Header.astro";
import Footer from "../components/Footer.astro";
---
<html lang="en">
<head>
<Header />
</head>
<body>
<Footer />
</body>
</html>
So far, our website has been completely static. In order to pass data between pages and components, we need to understand how props and slots work.
Components and layouts can define and accept props (short for properties) via the global Astro.props. Values passed through props are accessible to the component before rendering.
We can read props in our component like this:
---
// src/components/Header.astro
const { title } = Astro.props;
---
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator"
<title>{title}</title>
The value of title can be supplied when the component is called, which in the following example happens through the SiteLayout layout.
---
// src/layouts/SiteLayout.astro
import Header from "../components/Header.astro";
import Footer from "../components/Footer.astro";
---
<html lang="en">
<head>
<Header title = "Welcome my Astro Blog!" />
</head>
<body>
<Footer />
</body>
</html>
⚠️ Note that you need spaces surrounding the equal sign, i.e. title="Hello" is NOT correct. Instead, it should be: title = "Hello".
Slot elements create placeholders for content to be injected later. To see how it works, we can add a <slot /> element in src/layouts/SiteLayout.astro:
---
// src/layouts/SiteLayout.astro
import Header from "../components/Header.astro";
import Footer from "../components/Footer.astro";
---
<html lang="en">
<head>
<Header title = "Welcome my Astro Blog!" />
</head>
<body>
<slot />
<Footer />
</body>
</html>
Now the HTML inside <SiteLayout> is injected into the point where the slot is located.
---
// src/pages/index.astro
import SiteLayout from "../layouts/SiteLayout.astro";
---
<SiteLayout>
<p>This content is rendered in the slot</p>
</SiteLayout>
Nesting components, layouts, props, and slots give us the flexibility to create reusable UI files across the website.
Up to this point, we have not shipped any JavaScript to the user; everything is prerendered and served as pure HTML+CSS. How do we send make Astro send JavaScript to the browser? For that, we need to understand the islands architecture.
The island architecture pattern aims to reduce the amount of JavaScript needed browser-side. Less JavaScript means less data sent and less computational power required on the user’s device. An island is an autonomous component that bundles HTML, CSS, and — optionally — JavaScript. In the islands pattern, a page is made up of several independent islands.
The islands architecture allows combining static HTML, server-rendered content, and interactive client-rendered components on one page without conflicts.
Each island is prerendered, so there is no interactivity right after the page loads. Once the initial page is ready, the islands are converted into interactive content in a process called hydration. Hydration is a technique that converts static content delivered via static hosting or server-side rendering into a dynamic page by attaching event handlers to the HTML elements.
How hydration works. The first contentful paint happens right after all the HTML has been sent to the browser, which typically happens very quickly. The browser then requests and executes all the client-side JavaScript needed to make the page fully interactive.
An example showing how Astro implements islands is in order. Let’s first add a UI integration to the project. The following command installs @astrojs/preact and preact.
$ npx astro add preact
Let’s create a simple button to test the integration:
// src/components/MyButton.jsx
export default function MyButton() {
const clicked = () => { console.log('Hello!') };
return (
<div>
<button style={{ color: 'purple' }} onClick={clicked}>Click me</button>
</div>
)
}
As usual, Astro will try to strip away any JavaScript. So nothing would happen if we instantiated the component with <MyButton />. We need to tell Astro that we want this component treated as an island and hydrated accordingly by adding the template directive client:load:
---
import MyButton from "../components/MyButton.jsx";
---
<html lang="en">
<body>
<MyButton client:load />
</body>
</html>
Clicking the button should print “Hello!” in the browser console.
The client directive caused Astro to hydrate the component. There are five levels of hydration with different priorities:
Being a Node application, setting up an Astro build with CI/CD is very straightforward. We only need a couple of jobs.
A possible continuous integration pipeline for Astro.
The first job runs npm ci to populate node_modules. We use sem-version to select a current Node version.
checkout
sem-version node 19.4
npm ci
cache store
The second job runs npm run build and stores the built application (located in the dist folder) as a workflow artifact.
checkout
sem-version node 19.4
cache restore
npm run build
artifact push workflow dist/
Once the site is built, we can configure continuous deployment.
Depending on the nature of the web application, Astro can be deployed as a static site à la Hugo or Gatsby, in which case we only need something as simple as an S3 bucket or GitHub pages, or as a full-fledged server-side rendered (SSR) application, where we need JavaScript- or TypeScript-enabled endpoints.
Astro has built-in support for various popular deployment targets such as Netlify, Firebase, Vercel, and Deno. Some only support either SSR or static hosting, while others can do both.
Once we have chosen our deployment method, we can add a continuous deployment pipeline to automatically deploy the website on every change.
Here’s an example deployment pipeline that targets a Netlify static site.
The complete CI/CD workflow with continuous deployment to Netlify.
Pour référence, les commandes de travail sont les suivantes. Cela suppose que nous ayons déjà obtenu un jeton API et l'avons enregistré en tant que secret sur Semaphore avec les variables d'environnement NETLIFY_TOKEN et NETLIFY_SITE.
checkout
artifact pull workflow dist
npm install -g netlify-cli
netlify deploy --dir=dist --prod --auth $NETLIFY_TOKEN --site $NETLIFY_SITE
La popularité de ce projet a été tout simplement astronomique : au cours des cinq premiers mois depuis la sortie d'Astro 1.0, le projet a amassé plus de 25 000 étoiles sur GitHub. Le succès d'Astro n'est pas accidentel. L'équipe Astro a créé un framework Web qui offre une excellente ergonomie pour les développeurs et des sites Web à chargement rapide pour les utilisateurs, même s'ils sont sur des appareils à faible consommation ou des connexions lentes.
Merci d'avoir lu et bonne construction !
Source : https://semaphoreci.com
#astro
1595504520
It is well known that the ruby comments are used to leave notes or micro-docs within the code and is ignored by the Ruby Interpreter. But can we do other things with comments?
There are several other functions that comments can offer. In this article, we shall dive into some of the use cases of comments that can have certain desirable impacts on the Ruby interpreter. Each use case has been explained in detail making it easier for even beginners to understand.
Shebang is a “comment” that indicates the interpreter directive for the interpreter to be used when the file is run as an executable in *nix operating systems. This specific comment is not unique to Ruby. Many scripting languages make use of the shebang to make scripts executable in a simple manner.
in addition to specifying the interpreter directive, you can also specify the flags like — jit
or -w
which will automatically be passed on to the interpreter when the executable is run. Let’s take a look at how this can be done:
#magic-comments #ruby #frozen-string-literals #comment #encoding
1652688300
SqlFormatter
A lightweight php class for formatting sql statements.
It can automatically indent and add line breaks in addition to syntax highlighting.
History
I found myself having to debug auto-generated SQL statements all the time and wanted some way to easily output formatted HTML without having to include a huge library or copy and paste into online formatters.
I was originally planning to extract the formatting code from PhpMyAdmin, but that was 10,000+ lines of code and used global variables.
I saw that other people had the same problem and used Stack Overflow user losif's answer as a starting point. http://stackoverflow.com/a/3924147
Usage
The SqlFormatter class has a static method 'format' which takes a SQL string
as input and returns a formatted HTML block inside a pre tag.
Sample usage:
<?php require_once('SqlFormatter.php'); $query = "SELECT count(*),`Column1`,`Testing`, `Testing Three` FROM `Table1` WHERE Column1 = 'testing' AND ( (`Column2` = `Column3` OR Column4 >= NOW()) ) GROUP BY Column1 ORDER BY Column3 DESC LIMIT 5,10"; echo SqlFormatter::format($query);
Output:
If you don't want syntax highlighting and only want the indentations and line breaks, pass in false as the second parameter.
This is useful for outputting to error logs or other non-html formats.
<?php echo SqlFormatter::format($query, false);
Output:
There is a separate method 'highlight' that preserves all original whitespace and just adds syntax highlighting.
This is useful for sql that is already well formatted and just needs to be a little easier to read.
<?php echo SqlFormatter::highlight($query);
Output:
The compress method removes all comments and compresses whitespace.
This is useful for outputting queries that can be copy pasted to the command line easily.
-- This is a comment
SELECT
/* This is another comment
On more than one line */
Id #This is one final comment
as temp, DateCreated as Created FROM MyTable;
echo SqlFormatter::compress($query)
Output:
SELECT Id as temp, DateCreated as Created FROM MyTable;
If you want to keep all original whitespace formatting and just remove comments, you can use the removeComments method instead of compress.
-- This is a comment
SELECT
/* This is another comment
On more than one line */
Id #This is one final comment
as temp, DateCreated as Created FROM MyTable;
<?php echo SqlFormatter::removeComments($query);
Output:
SELECT
Id
as temp, DateCreated as Created FROM MyTable;
Another feature, which is unrelated to formatting, is the ability to break up a SQL string into multiple queries.
For Example:
DROP TABLE IF EXISTS MyTable; CREATE TABLE MyTable ( id int ); INSERT INTO MyTable (id) VALUES (1),(2),(3),(4); SELECT * FROM MyTable;
<?php $queries = SqlFormatter::splitQuery($sql);
Result:
DROP TABLE IF EXISTS MyTable
;CREATE TABLE MyTable ( id int )
;INSERT INTO MyTable (id) VALUES (1),(2),(3),(4)
;SELECT * FROM MyTable
;Why not just use explode(';', $sql)
or a regular expression?
The following example sql and others like it are impossible to split correctly using regular expressions, no matter how complex.
SELECT ";"; SELECT ";\"; a;";
SELECT ";
abc";
SELECT a,b #comment;
FROM test;
SqlFormatter breaks the string into tokens instead of using regular expressions and will correctly produce:
SELECT ";"
;SELECT ";\"; a;"
;SELECT "; abc"
;SELECT a,b #comment; FROM test
;Please note, the splitQuery method will still fail in the following cases:
Author: jdorn
Source Code: https://github.com/jdorn/sql-formatter/
License: MIT License
1661494080
nginx-conf
is a node module for making changes to an nginx configuration file programmatically.
npm install nginx-conf
This library has no dependencies.
Version 2.0.0
changed the way that single directives are accessed. In short, everything is now array-indexed.
// Pre 2.0.0:
conf.nginx.foo.bar._value;
// 2.0.0+
conf.nginx.foo[0].bar[0]._value;
Pretend you have an nginx config file like this one.
Note that all public methods are prefixed with _
so that they (hopefully) don't clash with nginx's directives.
Note: *_content_by_lua_block
directives are supported in >=v1.3.0
.
// vanilla JS: const NginxConfFile = require('nginx-conf').NginxConfFile;
import {NginxConfFile} from '../../';
const filename = `${__dirname}/../files/readme.conf`;
NginxConfFile.create(filename, function (err, conf) {
if (err || !conf) {
console.log(err);
return;
}
// reading values
console.log('user: ' + conf.nginx.user?.[0]._value);
console.log('http.server.listen: ' + conf.nginx.http?.[0].server?.[0].listen?.[0]._value);
console.log('http.server.location.root:' + conf.nginx.http?.[0].server?.[0].location?.[3].root?.[0]._value);
//writing values
//NginxConfFile.create() automatically sets up a sync, so that whenever
//a value is changed, or a node is removed/added, the file gets updated
//immediately
const onFlushed = () => {
console.log('finished writing to disk');
};
conf.on('flushed', onFlushed);
//listen to the flushed event to determine when the new file has been flushed to disk
if (conf.nginx.events?.[0].connections) {
conf.nginx.events[0].connections[0]._value = 1000;
//don't write to disk when something changes
conf.die(filename);
conf.nginx.events[0].connections[0]._value = 2000; //change remains local, not in /etc/nginx.conf
}
//write to a different file
conf.live(`${filename}.bak`);
//force the synchronization
conf.flush();
//adding and removing directives
if (conf.nginx.http) {
conf.nginx.http[0]._add('add_header', 'Cache-Control max-age=315360000, public');
console.log(conf.nginx.http[0].add_header?.[0]._value); //Cache-Control max-age=315360000, public
conf.nginx.http[0]._add('add_header', 'X-Load-Balancer lb-01');
conf.nginx.http[0]._add('add_header', 'X-Secure true');
console.log(conf.nginx.http[0].add_header?.[0]._value); //Cache-Control max-age=315360000, public
console.log(conf.nginx.http[0].add_header?.[1]._value); //X-Load-Balancer lb-01
console.log(conf.nginx.http[0].add_header?.[2]._value); //X-Secure true
conf.nginx.http[0]._remove('add_header'); //removes add_header[0]
conf.nginx.http[0]._remove('add_header', 1); //removes add_header[1]
}
//adding a new block
conf.nginx.http?.[0]._add('server');
conf.nginx.http?.[0].server?.[0]._add('listen', '80');
//that'll create something like this:
/*
server {
listen 80;
}
*/
//multiple blocks
conf.nginx.http?.[0]._add('server');
conf.nginx.http?.[0].server?.[1]._add('listen', '443');
/*
server {
listen 80;
}
server {
listen 443;
}
*/
// blocks with values:
conf.nginx.http?.[0].server?.[1]._add('location', '/');
conf.nginx.http?.[0].server?.[1].location?.[0]._add('root', '/var/www/example.com');
/*
server {
location / {
root /var/www/example.com;
}
}
*/
// you can also create empty blocks
conf.nginx.http?.[0]._add('events', '', []); // events { }
// lua blocks also work, but you can't put a mismatched "{" or "}" in a comment!
conf.nginx.http?.[0].server?.[0].location?.[0]._addVerbatimBlock('rewrite_by_lua_block', '\n\
ngx.say("this is a lua block!")\n\
res = ngx.location.capture("/memc",\n\
{ args = { cmd = "incr", key = ngx.var.uri } }\n\
)'
);
// remove old listener
conf.off('flushed', onFlushed);
// kill process when done writing to disk
conf.on('flushed', () => {
console.log('finished writing to disk, exiting');
process.exit();
});
conf.flush();
});
Support for comments is supported-ish. Comments are attached to directives, and will always be rendered above the directive when using toString()
(or _getString()
).
Comments can be added, removed and updated via the _comments
array on a node.
console.log(conf.nginx.events[0].use[0]._comments.length); // 1
console.log(conf.nginx.events[0].use[0]._comments[0]); // use [ kqueue | rtsig | epoll | /dev/poll | select | poll ];
//remove the comment
conf.nginx.events[0].use[0]._comments.splice(0, 1);
//add a new one
conf.nginx.events[0].use[0]._comments.push('my new comment');
console.log(conf.nginx.events[0].use[0]._comments.length); // 1
console.log(conf.nginx.events[0].use[0]._comments[0]); //my new comment
//update a comment's text
conf.nginx.events[0].use[0]._comments[0] = 'updated';
console.log(conf.nginx.events[0].use[0]._comments[0]); //updated
If the comment is in a weird place (like in the middle of a directive), it'll still be attached to the node. If it's after the directive (after the semicolon or closing brace), it will be attached to the next node, or ignored if it's at the end of the file.
Assuming this nginx configuration:
foo #comment
bar;
You will have this object structure:
console.log(conf.nginx.foo[0]._value); //bar
console.log(conf.nginx.foo[0]._comments[0]); //comment
But if the comment comes after:
foo bar;
#comment
console.log(conf.nginx.foo[0]._value); //bar
console.log(conf.nginx.foo[0]._comments.length); //0
Support for go template syntax is provided via NginxParserOptions
. By default, templating syntax is not supported.
To enable templating syntax, pass the following NginxParserOptions
to the parser.parse
or parser.parseFile
function(s):
{
templateSyntax: true
}
git clone git@github.com:tmont/nginx-conf.git
cd nginx-conf
npm install
npm test
If you're making changes, you should run npm run watch
in a separate terminal. tsc
will output the JavaScript in the dist/
directory. The tests reference the JavaScript files in dist/
, not the TypeScript files elsewhere.
Only the stuff in dist/
is included in the NPM package.
Author: tmont
Source Code: https://github.com/tmont/nginx-conf
License: MIT license
1650870267
In the previous chapters you've learnt how to select individual elements on a web page. But there are many occasions where you need to access a child, parent or ancestor element. See the JavaScript DOM nodes chapter to understand the logical relationships between the nodes in a DOM tree.
DOM node provides several properties and methods that allow you to navigate or traverse through the tree structure of the DOM and make changes very easily. In the following section we will learn how to navigate up, down, and sideways in the DOM tree using JavaScript.
You can use the firstChild
and lastChild
properties of the DOM node to access the first and last direct child node of a node, respectively. If the node doesn't have any child element, it returns null
.
<div id="main">
<h1 id="title">My Heading</h1>
<p id="hint"><span>This is some text.</span></p>
</div>
<script>
var main = document.getElementById("main");
console.log(main.firstChild.nodeName); // Prints: #text
var hint = document.getElementById("hint");
console.log(hint.firstChild.nodeName); // Prints: SPAN
</script>
Note: The
nodeName
is a read-only property that returns the name of the current node as a string. For example, it returns the tag name for element node,#text
for text node,#comment
for comment node,#document
for document node, and so on.
If you notice the above example, the nodeName
of the first-child node of the main DIV element returns #text instead of H1. Because, whitespace such as spaces, tabs, newlines, etc. are valid characters and they form #text nodes and become a part of the DOM tree. Therefore, since the <div>
tag contains a newline before the <h1>
tag, so it will create a #text node.
To avoid the issue with firstChild
and lastChild
returning #text or #comment nodes, you could alternatively use the firstElementChild
and lastElementChild
properties to return only the first and last element node, respectively. But, it will not work in IE 9 and earlier.
<div id="main">
<h1 id="title">My Heading</h1>
<p id="hint"><span>This is some text.</span></p>
</div>
<script>
var main = document.getElementById("main");
alert(main.firstElementChild.nodeName); // Outputs: H1
main.firstElementChild.style.color = "red";
var hint = document.getElementById("hint");
alert(hint.firstElementChild.nodeName); // Outputs: SPAN
hint.firstElementChild.style.color = "blue";
</script>
Similarly, you can use the childNodes
property to access all child nodes of a given element, where the first child node is assigned index 0. Here's an example:
<div id="main">
<h1 id="title">My Heading</h1>
<p id="hint"><span>This is some text.</span></p>
</div>
<script>
var main = document.getElementById("main");
// First check that the element has child nodes
if(main.hasChildNodes()) {
var nodes = main.childNodes;
// Loop through node list and display node name
for(var i = 0; i < nodes.length; i++) {
alert(nodes[i].nodeName);
}
}
</script>
The childNodes
returns all child nodes, including non-element nodes like text and comment nodes. To get a collection of only elements, use children
property instead.
<div id="main">
<h1 id="title">My Heading</h1>
<p id="hint"><span>This is some text.</span></p>
</div>
<script>
var main = document.getElementById("main");
// First check that the element has child nodes
if(main.hasChildNodes()) {
var nodes = main.children;
// Loop through node list and display node name
for(var i = 0; i < nodes.length; i++) {
alert(nodes[i].nodeName);
}
}
</script>