Wow Style tags in posts
-
So I'm working on a game and I chose nodeBB because of its customization ability and being in javascript (easy to edit and manipulate). I currently use the docker version to rollout nodebb with wordpress. Before I continue the docker version was pretty complicated to set up with lack of directions but I got it up and running.
I need to know if I did something a good or bad way. I currently have a restful api that has all the items in json format (over 3000 items). So essentially what I did was when nodebb is installed it reads that api and places them in public/items/ individually instead of all items being in one json file. I felt this was way faster then reading the entire json file for every single item.
I modified an extended version of a plugin that supported bbcodes (to lazy to write me own). I considered using mongoDB but the information doesn't change so i felt this was a utterly waste.
if (typeof (code) !== "undefined") { let item_id = code; const itemPath = path.join(__dirname, "../../../app/public/items/"+ item_id +".json"); try { if (fs.existsSync(itemPath)) { let rawItemData = fs.readFileSync(itemPath); let itemData = JSON.parse(rawItemData.toString()); return `<img src="http://api.delteria.com/resource/${itemData.properties.icon}" alt="Avatar" class="avatar"><span class="extended-markdown-tooltip" data-toggle="tooltip" title="${itemData.properties.description}"><span style="color: ${getRarity(itemData.controllerProperties.rarity)};">${itemData.properties.itemName}</span></span>`; } } catch(err) { console.error(err) }
Here is the progress
Should I have done this differently?
-
You haven't posted the entire code so not sure where that code is running. I am assuming it is running when posts are being parsed and you read the correct item json file and generate the img html.
There are a few things you can do to make this better.
- Don't use the sync methods these are bad for performance as they will halt the nodejs thread waiting for the operation to finish. Use fs.promises.* functions with await.
let rawItemData = await fs.promises.readFile(itemPath);
- You don't have to check if the file exists and then read it. If you try to read a file that doesn't exist it will throw an error so you can get rid of the fs.exists call.
try { let rawItemData = await fs.promises.readFile(itemPath); let itemData = JSON.parse(rawItemData.toString()); return `<img src="http://api.delteria.com/resource/${itemData.properties.icon}" alt="Avatar" class="avatar"><span class="extended-markdown-tooltip" data-toggle="tooltip" title="${itemData.properties.description}"><span style="color: ${getRarity(itemData.controllerProperties.rarity)};">${itemData.properties.itemName}</span></span>`; } catch(err) { console.error(err) }
- Reading from disk everytime the same item is rendered is probably wasteful you can cache the json data for the items after you load them. You can use the built in cache module we have.
const cache = require.main.require('./src/cache'); let item_id = code; try { let itemData = cache.get(`item_id:${item_id}`); if (!itemData) { const rawItemData = await fs.promises.readFile(itemPath); itemData = JSON.parse(rawItemData.toString()); cache.set(`item_id:${item_id}`, itemData); } return `<img src="http://api.delteria.com/resource/${itemData.properties.icon}" alt="Avatar" class="avatar"><span class="extended-markdown-tooltip" data-toggle="tooltip" title="${itemData.properties.description}"><span style="color: ${getRarity(itemData.controllerProperties.rarity)};">${itemData.properties.itemName}</span></span>`; } catch (err) { console.error(err) }
Make sure to test the code since I wrote it off the top of my head. For await to work the containing function needs to have the
async
keyword. -
very interesting will update it with some feedback
-
@baris said in Wow Style tags in posts:
You haven't posted the entire code so not sure where that code is running. I am assuming it is running when posts are being parsed and you read the correct item json file and generate the img html.
There are a few things you can do to make this better.
- Don't use the sync methods these are bad for performance as they will halt the nodejs thread waiting for the operation to finish. Use fs.promises.* functions with await.
let rawItemData = await fs.promises.readFile(itemPath);
- You don't have to check if the file exists and then read it. If you try to read a file that doesn't exist it will throw an error so you can get rid of the fs.exists call.
try { let rawItemData = await fs.promises.readFile(itemPath); let itemData = JSON.parse(rawItemData.toString()); return `<img src="http://api.delteria.com/resource/${itemData.properties.icon}" alt="Avatar" class="avatar"><span class="extended-markdown-tooltip" data-toggle="tooltip" title="${itemData.properties.description}"><span style="color: ${getRarity(itemData.controllerProperties.rarity)};">${itemData.properties.itemName}</span></span>`; } catch(err) { console.error(err) }
- Reading from disk everytime the same item is rendered is probably wasteful you can cache the json data for the items after you load them. You can use the built in cache module we have.
const cache = require.main.require('./src/cache'); let item_id = code; try { let itemData = cache.get(`item_id:${item_id}`); if (!itemData) { const rawItemData = await fs.promises.readFile(itemPath); itemData = JSON.parse(rawItemData.toString()); cache.set(`item_id:${item_id}`, itemData); } return `<img src="http://api.delteria.com/resource/${itemData.properties.icon}" alt="Avatar" class="avatar"><span class="extended-markdown-tooltip" data-toggle="tooltip" title="${itemData.properties.description}"><span style="color: ${getRarity(itemData.controllerProperties.rarity)};">${itemData.properties.itemName}</span></span>`; } catch (err) { console.error(err) }
Make sure to test the code since I wrote it off the top of my head. For await to work the containing function needs to have the
async
keyword.Firstly I would like to thank you for such a rapid response, and very helpful pointers. It led me to go and read up on the two different cache libraries it uses.
But it seems I couldn't get it to work, this portion of the edit is a plugin and not hard coded. I did intend to use your exact method but fs."promises" can't be recognized and I'm using node:LTS as my docker image (not sure if that matters). So I ended up going with a very similar method "const readFile = util.promisify(fs.readFile);".
if (typeof (code) !== "undefined") { let item_id = code; try { let itemData = cache.get(`item_id:${item_id}`); if (!itemData) { const itemPath = path.join(__dirname, "../../../app/public/items/" + item_id + ".json"); const readFile = util.promisify(fs.readFile); let rawItemData = await readFile(itemPath, `utf-8`); itemData = JSON.parse(rawItemData.toString()); cache.set(`item_id:${item_id}`, itemData); } return `<img src="http://api.delteria.com/resource/${itemData.properties.icon}" alt="Avatar" class="avatar"><span class="extended-markdown-tooltip" data-toggle="tooltip" title="${itemData.properties.description}"><span style="color: ${getRarity(itemData.controllerProperties.rarity)};">${itemData.properties.itemName}</span></span>`; } catch (err) { console.error("Issue Loading Item Tag: " + err); } /* let item_id = code; const itemPath = path.join(__dirname, "../../../app/public/items/"+ item_id +".json"); try { if (fs.existsSync(itemPath)) { let rawItemData = fs.readFileSync(itemPath); let itemData = JSON.parse(rawItemData.toString()); return `<img src="http://api.delteria.com/resource/${itemData.properties.icon}" alt="Avatar" class="avatar"><span class="extended-markdown-tooltip" data-toggle="tooltip" title="${itemData.properties.description}"><span style="color: ${getRarity(itemData.controllerProperties.rarity)};">${itemData.properties.itemName}</span></span>`; } } catch(err) { console.error(err) } */ }
But I'll continue to work on it tomorrow after work, to see if i can figure it out.
-
If you are seeing
[object Promise]
in your output it could be due to a missing await or returning a promise instead of the html string. You didn't post the surrounding function this code is in or which plugin hook it is using so can't really tell what is causing it.