Skip to content

Commit

Permalink
fix: introduce Website Extensions (#4344)
Browse files Browse the repository at this point in the history
  • Loading branch information
adrians5j authored and brunozoric committed Nov 5, 2024
1 parent ccc1ff0 commit bf5706d
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 1 deletion.
5 changes: 5 additions & 0 deletions packages/cli-plugin-extensions/src/extensions/Extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { WorkspaceExtension } from "./WorkspaceExtension";
import loadJson from "load-json-file";
import { PackageJson } from "@webiny/cli-plugin-scaffold/types";
import path from "path";
import { WebsiteExtension } from "~/extensions/WebsiteExtension";

type PackageJsonPath = string;

Expand All @@ -28,6 +29,10 @@ export class Extension extends AbstractExtension {
this.extension = new PbElementExtension(params);
break;
}
case "website": {
this.extension = new WebsiteExtension(params);
break;
}
case "workspace": {
this.extension = new WorkspaceExtension(params);
break;
Expand Down
115 changes: 115 additions & 0 deletions packages/cli-plugin-extensions/src/extensions/WebsiteExtension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { AbstractExtension } from "./AbstractExtension";
import path from "path";
import { EXTENSIONS_ROOT_FOLDER } from "~/utils/constants";
import chalk from "chalk";
import { JsxFragment, Node, Project } from "ts-morph";
import { formatCode } from "@webiny/cli-plugin-scaffold/utils";
import { updateDependencies, updateWorkspaces } from "~/utils";

export class WebsiteExtension extends AbstractExtension {
async link() {
await this.addPluginToWebsiteApp();

// Update dependencies list in package.json.
const packageJsonPath = path.join("apps", "website", "package.json");
await updateDependencies(packageJsonPath, {
[this.params.packageName]: "1.0.0"
});

await updateWorkspaces(this.params.location);
}

getNextSteps(): string[] {
let { location: extensionsFolderPath } = this.params;
if (!extensionsFolderPath) {
extensionsFolderPath = `${EXTENSIONS_ROOT_FOLDER}/${this.params.name}`;
}

const watchCommand = `yarn webiny watch website --env dev`;
const indexTsxFilePath = `${extensionsFolderPath}/src/index.tsx`;

return [
`run ${chalk.green(watchCommand)} to start a new local development session`,
`open ${chalk.green(indexTsxFilePath)} and start coding`,
`to install additional dependencies, run ${chalk.green(
`yarn workspace ${this.params.packageName} add <package-name>`
)}`
];
}

private async addPluginToWebsiteApp() {
const { name, packageName } = this.params;

const extensionsFilePath = path.join("apps", "website", "src", "Extensions.tsx");

const ucFirstName = name.charAt(0).toUpperCase() + name.slice(1);
const componentName = ucFirstName + "Extension";

const importName = "{ Extension as " + componentName + " }";
const importPath = packageName;

const project = new Project();
project.addSourceFileAtPath(extensionsFilePath);

const source = project.getSourceFileOrThrow(extensionsFilePath);

const existingImportDeclaration = source.getImportDeclaration(importPath);
if (existingImportDeclaration) {
return;
}

let index = 1;

const importDeclarations = source.getImportDeclarations();
if (importDeclarations.length) {
const last = importDeclarations[importDeclarations.length - 1];
index = last.getChildIndex() + 1;
}

source.insertImportDeclaration(index, {
defaultImport: importName,
moduleSpecifier: importPath
});

const extensionsIdentifier = source.getFirstDescendant(node => {
if (!Node.isIdentifier(node)) {
return false;
}

return node.getText() === "Extensions";
});

if (!extensionsIdentifier) {
throw new Error(
`Could not find the "Extensions" React component in "${extensionsFilePath}". Did you maybe change the name of the component?`
);
}

const extensionsArrowFn = extensionsIdentifier.getNextSibling(node =>
Node.isArrowFunction(node)
);
if (!extensionsArrowFn) {
throw new Error(
`Could not find the "Extensions" React component in "${extensionsFilePath}". Did you maybe change its definition? It should be an arrow function.`
);
}

const extensionsArrowFnFragment = extensionsArrowFn.getFirstDescendant(node => {
return Node.isJsxFragment(node);
}) as JsxFragment;

const extensionsArrowFnFragmentChildrenText = extensionsArrowFnFragment
.getFullText()
.replace("<>", "")
.replace("</>", "")
.trim();

extensionsArrowFnFragment.replaceWithText(
`<><${componentName}/>${extensionsArrowFnFragmentChildrenText}</>`
);

await source.save();

await formatCode(extensionsFilePath, {});
}
}
3 changes: 2 additions & 1 deletion packages/cli-plugin-extensions/src/promptQuestions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ export const promptQuestions: QuestionCollection = [
choices: [
{ name: "Admin extension", value: "admin" },
{ name: "API extension", value: "api" },
{ name: "Page Builder element", value: "pbElement" }
{ name: "Page Builder element", value: "pbElement" },
{ name: "Website extension", value: "website" }
]
},
{
Expand Down
13 changes: 13 additions & 0 deletions packages/cli-plugin-extensions/templates/website/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "PACKAGE_NAME",
"main": "src/index.tsx",
"version": "1.0.0",
"keywords": [
"webiny-extension",
"webiny-extension-type:admin"
],
"dependencies": {
"react": "18.2.0",
"@webiny/app-website": "0.0.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from "react";

export const Extension = () => {
return <>{/* Your code here. */}</>;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "BASE_TSCONFIG_PATH",
"include": ["src"]
}

0 comments on commit bf5706d

Please sign in to comment.