Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use near-bos-webcomponent #143

Merged
merged 4 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,19 @@ It is easy to build and distribute a custom gateway using the [near-bos-webcompo

The bos-workspace dev server is specially configured with the near-bos-webcomponent to automatically set the `rpc` attribute with the [proxy-rpc](#proxy-rpc).

## Deploying to Web4

If you specify an `index` in your bos.config.json, then bos-workspace will display your widgets through the latest version of [near-bos-webcomponent](https://github.com/nearbuilders/near-bos-webcomponent), or the gateway provided via the `-g` flag.

This involves some html manipulation in order to set the web component's attributes. The html that is created can be found in the designated destination (defaults to `/build`). This html can be used to easily deploy your site with widgets to [web4](https://github.com/vgrichina/web4).

1. Be sure to have deployed a web4 smart contract, such as the [web4-min-contract](https://github.com/vgrichina/web4-min-contract)
2. Move the output index.html to your `/public` or `/dist` if not using a bundler.
3. [TEMP] Remove the rpc and config attributes from `near-social-viewer` element.
4. Run [web4 deploy](https://github.com/vgrichina/web4-deploy) with src being the directory that holds this index.html and the account you have a contract deployed to.

**This is a rough first draft of the implementation and will be improved upon.**

## Commands

You can run `bw` or `bos-workspace` to see the list of commands.
Expand Down
19 changes: 10 additions & 9 deletions lib/dev.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { readJson, writeJson } from "fs-extra";
import { Gaze } from "gaze";
import path from "path";
import { Server as IoServer } from "socket.io";
import { buildApp } from "./build";
import { BaseConfig, loadConfig } from "./config";
import { startDevServer } from "./server";
import { startSocket } from "./socket";
import { Network } from "./types";
import { loopThroughFiles, readFile } from "./utils/fs";
import { mergeDeep, substractDeep } from "./utils/objects";
import { startFileWatcher } from "./watcher";
import { buildApp } from "@/lib/build";
import { BaseConfig, loadConfig } from "@/lib/config";
import { startDevServer } from "@/lib/server";
import { startSocket } from "@/lib/socket";
import { Network } from "@/lib/types";
import { loopThroughFiles, readFile, readJson, writeJson } from "@/lib/utils/fs";
import { mergeDeep, substractDeep } from "@/lib/utils/objects";
import { startFileWatcher } from "@/lib/watcher";

var appSrcs = [], appDists = [];
var appDevJsons = [];
Expand All @@ -25,6 +24,7 @@ export type DevOptions = {
network?: Network; // network to use
gateway?: string | boolean; // path to custom gateway dist, or false to disable
index?: string; // widget to use as index
output?: string; // output directory
};

/**
Expand Down Expand Up @@ -53,6 +53,7 @@ export async function dev(src: string, dest: string, opts: DevOptions) {
appDists = [dist];
appDevJsons = [devJson];
appDevJsonPath = devJsonPath;
opts.output = dist;
appDevOptions = opts;
const server = startDevServer(appSrcs, appDists, appDevJsonPath, appDevOptions);

Expand Down
122 changes: 88 additions & 34 deletions lib/gateway.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,8 @@

import { DevOptions } from "./dev";
import axios from "axios";

import { JSDOM } from "jsdom";

function renderAttribute(name, value) {
return value !== undefined ? `${name}="${value}"` : "";
}

function htmlStringify(json) {
return JSON.stringify(json)
.replace(/&/g, "&")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;");
}

export const handleReplacements = (html: string, opts: DevOptions): string => {
const envConfig = JSON.stringify({
enableHotReload: opts.hot,
Expand All @@ -42,30 +29,97 @@ function normalizeHtml(html) {
return html.replace(/\s+/g, ' ').trim();
}

const contentCache = {};

export async function fetchAndCacheContent(url) {
if (!contentCache[url]) {
const response = await axios.get(url);
contentCache[url] = response.data;
}
return contentCache[url];
}

export function modifyIndexHtml(content: string, opts: DevOptions) {
export function modifyIndexHtml(content: string, opts: DevOptions, dependencies: string[]) {
const dom = new JSDOM(content);
const document = dom.window.document;

const viewer = document.querySelector('near-social-viewer');
// Add script tags for each dependency
dependencies.forEach((dependency: string) => {
const script = document.createElement('script');
script.src = dependency;
script.defer = true;
document.head.appendChild(script);
});

const elementTag = "near-social-viewer";

// Create and configure the near-social-viewer element
const container = document.getElementById("bw-root");
const element = document.createElement(elementTag); // this could be configurable
element.setAttribute("src", opts.index);
element.setAttribute("rpc", `http://127.0.0.1:${opts.port}/api/proxy-rpc`);
element.setAttribute("network", opts.network);

if (viewer) {
viewer.setAttribute('src', opts.index);
viewer.setAttribute('rpc', `http://127.0.0.1:${opts.port}/api/proxy-rpc`);
viewer.setAttribute('network', opts.network);
if (opts.hot) {
viewer.setAttribute('enablehotreload', "");
const config = {
dev: {
hotreload: {
enabled: opts.hot
}
},
vm: {
features: {
enableComponentSrcDataKey: true
}
}
}
};

element.setAttribute('config', JSON.stringify(config));

container.appendChild(element);

// Add wallet selector

// Stylesheet
const styleLink = document.createElement('link');
styleLink.rel = 'stylesheet';
styleLink.href = 'https://cdn.jsdelivr.net/npm/@near-wallet-selector/[email protected]/styles.css';
document.head.appendChild(styleLink);

// Import wallets and setup selector
const webcomponentapp = document.createElement('script');
// We could configure wallets from bos.config.json
webcomponentapp.textContent = `
import { setupWalletSelector } from "@near-wallet-selector/core";
import { setupMyNearWallet } from "@near-wallet-selector/my-near-wallet";
import { setupHereWallet } from "@near-wallet-selector/here-wallet";
import { setupMeteorWallet } from "@near-wallet-selector/meteor-wallet";
import { setupSender } from "@near-wallet-selector/sender";
import { setupNightly } from "@near-wallet-selector/nightly";
import { setupMintbaseWallet } from "@near-wallet-selector/mintbase-wallet";

const selector = await setupWalletSelector({
network: "${opts.network}",
modules: [
setupMyNearWallet(),
setupHereWallet(),
setupMeteorWallet(),
setupSender(),
setupNightly(),
setupMintbaseWallet()
],
});

const viewer = document.querySelector("${elementTag}");
viewer.selector = selector;
`;
webcomponentapp.type = 'module';
document.body.appendChild(webcomponentapp);

return dom.serialize();
}
}

// // This should be modified to only run when necessary... only needs to be done when initializing the project
// // or when the dependencies change (which could just be managed by here... really just need to add it to the json.)
// export async function importPackages(html: string): Promise<string> {
// try {
// const { Generator } = await import('@jspm/generator');
// const generator = new Generator();
// return await generator.htmlInject(html, {
// trace: true,
// esModuleShims: true
// });
// } catch (error) {
// console.error('Error importing or using @jspm/generator:', error);
// return html; // Return original HTML if there's an error
// }
// }
2 changes: 1 addition & 1 deletion lib/repository.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AccountID, Log } from "@/lib/types";
import { DEFAULT_CONFIG, readConfig } from "./config";
import { DEFAULT_CONFIG, readConfig } from "@/lib/config";
import fs, { existsSync, outputFile, writeFile } from "fs-extra";
import path from "path";
import { SHA256 } from "crypto-js";
Expand Down
Loading
Loading