Initial commit

Co-Authored-By: kotte <14197736+mrtamagotchi@users.noreply.github.com>
Co-Authored-By: mikaeltellhed <2311083+mikaeltellhed@users.noreply.github.com>
Co-Authored-By: Tore Knudsen <18231882+torekndsn@users.noreply.github.com>
Co-Authored-By: Michael Cartner <32543275+michaelcartner@users.noreply.github.com>
This commit is contained in:
Eric Tuvesson
2023-09-05 12:08:55 +02:00
commit 53f0d6320e
2704 changed files with 76354 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
---
title: Change nodes at build time
hide_title: true
---
<head>
<meta name="robots" content="noindex,nofollow,noarchive" />
</head>
# Change nodes at build time
:::note
This is recommended to only use in 2.7.x.
If using it in 2.6.x, you will change the current project
which will not be temporary during building.
:::
```js
module.exports = {
async onPreBuild(context) {
// Get all the "Function" nodes
const functionNodes = context.project.getNodesWithType('JavaScriptFunction');
functionNodes.forEach((node) => {
// Replace all "Hello World" to "Hello" in the scripts
node.parameters.functionScript = node.parameters.functionScript
.replace("Hello World", "Hello");
});
},
};
```

View File

@@ -0,0 +1,147 @@
---
title: Create a build script
hide_title: true
---
<head>
<meta name="robots" content="noindex,nofollow,noarchive" />
</head>
# Build scripts
Noodl has a way where you can hook into the different build events that
are triggered from the editor.
:::danger
This is an experimental feature, that might be changed in the future.
:::
### Where to use it?
- [Generate a Sitemap and static pages](/javascript/extending/build-script/sitemap-and-seo)
- [Change nodes at build time](/javascript/extending/build-script/change-nodes-at-build-time)
## Create a build script
To add a build script it has to be placed inside a folder in the project.
As long as the file ends with `.build.js` it will be picked up by Noodl.
The execution order of the build scripts are based on alphabetical order.
```
my-noodl-project/
.noodl/
build-scripts/
[HERE]
```
### Example
Here is an example of what kind of events you can listen to:
```js
module.exports = {
async onPreBuild(context) {
// Occurs before the build.
},
async onPostBuild(context) {
// Occurs after the build.
},
async onPreDeploy(context) {
// Occurs before the build is deployed.
},
async onPostDeploy(context) {
// Occurs after the build is deployed.
},
};
```
## What is Context?
Context is a little different in each method,
but generally have the same methods.
:::note
More documentation to come later!
:::
### General
```ts
workspaceId: string;
project: ProjectModel;
environment: {
name: string;
description: string;
masterKey: string;
appId: string;
} | undefined;
/**
*
* @param options
* @param callback
*/
activity(options: { message: string; successMessage?: string; }, callback: () => Promise<void>): Promise<void>;
/**
*
* @param type
* @param message
*/
notify(type: 'notice' | 'success' | 'error', message: string): void;
/**
* Returns a list of all the pages with absolute paths.
*
* @returns [
* {
* title: "page title",
* path: "/path-1/path-2",
* meta: {}
* },
* // ...
* ]
*/
getPages(options: {
expandPaths?: (route: RouteNode) => Promise<string[]>;
}): Promise<readonly PageObject[]>;
/**
* Create a index.html page similar to the one created for the web app.
*
* @returns a string containg the HTML code.
*/
createIndexPage(options: {
/**
* Override the title from project settings.
*
* Default: undefined
*/
title?: string;
/**
* Append the headcode from the project settings.
*
* Default: undefined
*/
headCode?: string;
}): Promise<string>;
/**
* Returns a traversal graph of the nodes.
*
* @param selector
* @returns
*/
graphTraverse(
selector: (node: NodeGraphModel.Node) => boolean,
options: NodeGraphTraverserOptions
): NodeGraphTraverser;
```

View File

@@ -0,0 +1,196 @@
---
title: Build script that generate Sitemap and static pages
hide_title: true
---
<head>
<meta name="robots" content="noindex,nofollow,noarchive" />
</head>
# Generate a Sitemap and static pages
Having a `sitemap.xml` is very important for SEO,
so that search engines can build up a good map on the website.
With Noodl we can create build scripts that will alter the files after building.
What is really cool with this feature is that you can find all the information on
how the project is built, so we can find all the Pages nodes and generate a nice
sitemap and even create static index.html files to improve the SEO even more!
## Examples
Here are 2 examples of a script that generates a sitemap from all the pages.
### Static pages for Sitemap.xml
In case you don't have any dynamic pages, this script is really easy to use.
```js
const fs = require("fs");
/**
* Sitemap class that helps us build the sitemap XML.
*/
class Sitemap {
constructor() {
this.urls = [];
}
add(entry) {
this.urls.push(entry);
}
toXml() {
let xml = `<urlset
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"
>`;
xml += this.urls
.map((item) => {
let entry = `<url>`;
Object.keys(item).forEach((key) => {
entry += `<${key}>${item[key]}</${key}>`;
});
return entry + `</url>`;
})
.join("");
return xml + `</urlset>`;
}
}
module.exports = {
async onPostBuild(context) {
/**
* this.getPages() returns a flat array of all the pages,
* like this:
*
* [
* {
* title: "page title",
* path: "/path-1/path-2",
* }
* ]
*
*/
const pages = await context.getPages();
// Create our Sitemap class
const sitemap = new Sitemap();
// Loop over all the pages
pages.forEach((page) => {
// Add the page to the sitemap with
// the sitemap tags we want to use.
//
// Here is what kind of tags there are:
// https://www.sitemaps.org/protocol.html
sitemap.add({
// NOTE: In this example the path is not an absolute URL, which is required to make sitemaps work correctly.
loc: page.path,
changefreq: "weekly",
priority: 0.5,
});
});
// Write our sitemap.xml to the outputPath
//
// if you are deploying via our cloud service
// this will also upload the file.
await fs.promises.writeFile(
`${context.outputPath}/sitemap.xml`,
sitemap.toXml()
);
},
};
```
### Dynamic pages for Sitemap.xml
To make this one work you have to provide the information required by Noodl
to understand what your dynamic pages have.
```js
// We can do that by sending more information to the "getPages" method.
const pages = await context.getPages({
// Async function that is called for each page that has variables.
async expandPaths(route) {
// Check the current page path.
if (route.current.path === "page-3/{id}") {
// Return a list of our expanded paths.
return [
{
title: "My custom title",
path: "page-3/0",
meta: {
description: "My description",
keywords: "",
},
},
{
path: "page-3/1",
},
{
path: "page-3/2",
},
];
}
// Return the default value.
// this will not be called unless there is a variable in the path.
// So we are returning an invalid path here.
return [
{
path: route.current.path,
},
];
},
});
// ...
// To access the meta data from the pages we can call
// pages[0].meta
```
### Generate static pages
We can expand on the previous example with dynamic pages for Sitemap.xml.
In this case we want to take all the information and write a index.html file
for each page.
```js
const fs = require('fs');
const path = require('path');
// ...
// Loop over all the pages
for (let index = 0; index < pages.length; index++) {
const page = pages[index];
// Create the filepath where we want to save the new index.html file.
const pageDir = path.join(context.outputPath, page.path);
// Generate a index.html file with our custom title and headcode.
const content = await context.createIndexPage({
title: page.title,
headCode: `
<meta name="description" content="${page.meta.description}">
<meta name="keywords" content="${page.meta.keywords}">
`,
});
// Create all the folders to the path.
await fs.promises.mkdir(pageDir, {
recursive: true,
});
// Save our new index.html file.
await fs.promises.writeFile(path.join(pageDir, "index.html"), content);
}
```