diff --git a/package.json b/package.json index ce652462..cd366453 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,6 @@ "mdast-util-to-string": "^4.0.0", "prettier": "^3.5.3", "prettier-plugin-astro": "^0.14.1", - "reading-time": "^1.5.0", "remark-breaks": "^4.0.0", "typescript": "^5.8.2", "unist-util-filter": "^5.0.1" diff --git a/tools/remark-reading-time.mjs b/tools/remark-reading-time.mjs index f3a592b5..8824bc47 100644 --- a/tools/remark-reading-time.mjs +++ b/tools/remark-reading-time.mjs @@ -1,4 +1,3 @@ -import getReadingTime from "reading-time"; import { toString } from "mdast-util-to-string"; import { filter } from "unist-util-filter"; @@ -6,6 +5,10 @@ import assert from "node:assert/strict"; const WORDS_PER_MINUTE = 265; +const segmenter = new Intl.Segmenter("en-US", { + granularity: "word", +}); + // Food for thoughts: have 2 different metrics for images & code blocks. // And use the image size as a baseline (bigger images will take more time than smaller ones), // and same for code blocks: larger code blocks should take more time. @@ -41,11 +44,11 @@ assert.equal(getSecondsAddedByImages(14), (totalForTest += 3)); export function remarkReadingTime() { return (tree, { data }) => { - let nbOfImages = 0; + let imagesCount = 0; const filteredTree = filter(tree, (node) => { // Treat images & code as "meta content" if (node.type === "image" || node.type === "code") { - nbOfImages++; + imagesCount++; } return ( node.type !== "code" && // Remove code blocks (easily read) @@ -62,31 +65,23 @@ export function remarkReadingTime() { // - https://help.medium.com/hc/en-us/articles/214991667-Read-time (for 265WPM) // - https://mediumcourse.com/how-is-medium-article-read-time-calculated/ (for the image timing) - const readingTime = getReadingTime(textOnPage); - - // `readingTime` contains a few information: - // - `text`: Human readable duration, like "3 min read", - // - `words`: The total word count - // - `minutes`: Total reading time duration in minutes - // - `time`: Total reading time duration in milliseconds - // As we want to manipulate this data manually, we'll just use `words` - - const words = readingTime.words; + const wordsCount = [...segmenter.segment(textOnPage)].filter( + ({ isWordLike }) => isWordLike, + ).length; - let time = Math.round((words / WORDS_PER_MINUTE) * 60_000); // round to avoid issues with floats + let totalMs = Math.round((wordsCount / WORDS_PER_MINUTE) * 60_000); // round to avoid issues with floats - const nbOfImagesBellow10 = Math.min(nbOfImages, 10); - const timeAddedByImages = getSecondsAddedByImages(nbOfImages) * 1000; // to milliseconds - time += timeAddedByImages; + const nbOfImagesBellow10 = Math.min(imagesCount, 10); + const timeAddedByImages = getSecondsAddedByImages(imagesCount) * 1000; // to milliseconds + totalMs += timeAddedByImages; - const minutes = time / 60_000; - const displayedText = Math.ceil(minutes.toFixed(2)) + " min read"; + const minutes = totalMs / 60_000; + const displayedText = Math.ceil(minutes) + " min read"; const finalReadingTime = { - words, - time, - minutes, - displayedText, + words: wordsCount, // The total word count + minutes, // Total reading time duration in minutes + displayedText, // Human readable duration, like "3 min read" }; data.astro.frontmatter.readingTime = finalReadingTime; diff --git a/yarn.lock b/yarn.lock index 325b8bd3..63c71a18 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7788,7 +7788,6 @@ __metadata: react-dom: "npm:^19.1.0" react-dom-18: "patch:react-dom@npm%3A18.3.1#~/.yarn/patches/react-dom-npm-18.3.1-a805663f38.patch" react-konva: "npm:^19.0.3" - reading-time: "npm:^1.5.0" remark-breaks: "npm:^4.0.0" reveal.js: "npm:^5.2.1" typescript: "npm:^5.8.2" @@ -8049,13 +8048,6 @@ __metadata: languageName: node linkType: hard -"reading-time@npm:^1.5.0": - version: 1.5.0 - resolution: "reading-time@npm:1.5.0" - checksum: 10c0/0f730852fd4fb99e5f78c5b0cf36ab8c3fa15db96f87d9563843f6fd07a47864273ade539ebb184b785b728cde81a70283aa2d9b80cba5ca03b81868be03cabc - languageName: node - linkType: hard - "recma-build-jsx@npm:^1.0.0": version: 1.0.0 resolution: "recma-build-jsx@npm:1.0.0"