Add Dynamic Import / Code Splitting for Tool Components (#48)#57
Add Dynamic Import / Code Splitting for Tool Components (#48)#57Shalini828 wants to merge 1 commit intobetterbugs:developfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR aims to reduce initial bundle size by moving development tool components toward dynamic imports/code-splitting, while also adding new tool components and some shared UI/refactors.
Changes:
- Refactors
developmentToolsRoutesto store component references (instead of JSX) and updates[slug]/page.tsxto render those components. - Adds new tools/content (JSON→CSV, cURL→Code) and a reusable
CopyButton. - Updates the bcrypt generator to use
bcryptjsand adds new dependencies.
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| package.json | Adds bcryptjs and curlconverter dependencies (plus bcrypt types). |
| package-lock.json | Lockfile updates for new deps and engine metadata. |
| app/libs/developmentToolsConstant.tsx | Adds content/SEO copy for JSON→CSV and cURL→Code tools. |
| app/libs/constants.tsx | Refactors developmentToolsRoutes, adds new PATHS/category entries, introduces one dynamic import. |
| app/components/ui/CopyButton.tsx | New reusable copy-to-clipboard button using react-toastify. |
| app/components/developmentToolsComponent/wordCounterComponent.tsx | Replaces/augments UI with the new CopyButton. |
| app/components/developmentToolsComponent/jsonValidator.tsx | Adds “Fix Common Errors” smart repair action. |
| app/components/developmentToolsComponent/jsonToTxt.tsx | Refactors copy behavior to use CopyButton. |
| app/components/developmentToolsComponent/jsonToCsvConverter.tsx | Adds new JSON→CSV conversion tool implementation. |
| app/components/developmentToolsComponent/curlToCodeConverter.tsx | Adds new cURL→code converter tool implementation. |
| app/components/developmentToolsComponent/bcryptGenerator.tsx | Switches hashing/verification to bcryptjs. |
| app/[slug]/page.tsx | Renders tool components from developmentToolsRoutes as component references. |
| CHANGELOG.md | Adds release notes entries for new UI + bcrypt changes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (p.auth) { | ||
| const creds = `${p.auth.user}:${p.auth.password}`; | ||
| const encoded = Buffer.from(creds).toString("base64"); | ||
| headerEntries.push(["Authorization", `Basic ${encoded}`]); | ||
| } | ||
|
|
There was a problem hiding this comment.
generateNodeJs also uses Buffer.from(...).toString('base64') while generating the output. Since this executes in the browser, it will throw when -u/--user is present. Switch to a browser-safe encoder or output code that performs the encoding within the generated Node.js snippet instead of inside the generator.
| "@types/turndown": "5.0.5", | ||
| "animejs": "3.2.2", | ||
| "antd": "5.16.2", | ||
| "curlconverter": "^4.12.0", |
There was a problem hiding this comment.
curlconverter is added as a runtime dependency but is not imported/used anywhere in the app code. This increases install size and (depending on bundling) can increase client bundle size; either remove it or wire the cURL tool to use it.
| "curlconverter": "^4.12.0", |
| import CurlToCodeConverter from '../components/developmentToolsComponent/curlToCodeConverter'; | ||
| import YAMLFormatterAndBeautifier from '../components/developmentToolsComponent/yamlFormatterAndBeautifier'; | ||
|
|
||
| import type { ComponentType } from "react"; | ||
| import dynamic from "next/dynamic"; | ||
| const Base64Encoder = dynamic( | ||
| () => import('../components/developmentToolsComponent/base64Encoder'), | ||
| { ssr: false, | ||
| loading: () => <p className="text-white">Loading tool...</p>, | ||
| } | ||
| ); |
There was a problem hiding this comment.
This file still statically imports a large number of tool components at the top, so they will still be bundled eagerly; only Base64Encoder is using next/dynamic here. To actually achieve code-splitting, the route map should avoid static imports and instead define each tool component via dynamic(() => import(...), { ssr: false }) (or equivalent lazy mapping).
| component: <RoundingCalculator />, | ||
| component: RoundingCalculator , | ||
| }, | ||
| { |
There was a problem hiding this comment.
PATHS.CSV_TO_TEXT_CONVERTER is defined and referenced elsewhere, but there is no corresponding entry in developmentToolsRoutes. As a result, navigating to /csv-to-text-converter will render the page without the tool component. Re-add the missing route entry mapping to CsvToTextConverter.
| { | |
| { | |
| path: PATHS.CSV_TO_TEXT_CONVERTER, | |
| component: CsvToTextConverter , | |
| }, | |
| { |
| step_key: 'Step 2:', | ||
| step_title: 'Configure options:', | ||
| step_description: | ||
| 'Choose your delimiter (comma, semicolon, or tab), decide whether to include headers, and enable nested object flattening if needed.', |
There was a problem hiding this comment.
The JSON-to-CSV tool copy says the delimiter can be comma/semicolon/tab, but the implemented UI currently only offers comma and semicolon. Either add a tab option in the tool component or update this text so the instructions match actual behavior.
| 'Choose your delimiter (comma, semicolon, or tab), decide whether to include headers, and enable nested object flattening if needed.', | |
| 'Choose your delimiter (comma or semicolon), decide whether to include headers, and enable nested object flattening if needed.', |
| import React, { useState } from "react"; | ||
| import { Copy, Check } from "@phosphor-icons/react"; | ||
| import { toast } from "react-toastify"; | ||
|
|
||
| interface CopyButtonProps { | ||
| text: string; | ||
| variant?: "icon" | "text"; | ||
| className?: string; | ||
| } | ||
|
|
||
| const CopyButton: React.FC<CopyButtonProps> = ({ | ||
| text, | ||
| variant = "icon", | ||
| className = "", | ||
| }) => { | ||
| const [copied, setCopied] = useState(false); | ||
|
|
||
| const handleCopy = async () => { | ||
| if (!text) return; | ||
|
|
||
| try { | ||
| await navigator.clipboard.writeText(text); | ||
| setCopied(true); | ||
| toast.success("Copied!"); | ||
| setTimeout(() => setCopied(false), 2000); | ||
| } catch (err) { | ||
| toast.error("Failed to copy"); | ||
| } |
There was a problem hiding this comment.
CopyButton calls toast.success/error, but the app doesn't render a global ToastContainer (and this component also doesn't render one). In places where CopyButton is used (e.g. Word Counter / JSON→TXT), the toast will not display and toastify CSS may not be loaded. Consider adding a single ToastContainer + toastify CSS import at the app root, or refactor CopyButton to not depend on toastify UI.
| const flattenObject = (obj: any, prefix = ""): Record<string, any> => { | ||
| const result: Record<string, any> = {}; | ||
| for (const key in obj) { | ||
| if (!obj.hasOwnProperty(key)) continue; |
There was a problem hiding this comment.
flattenObject uses obj.hasOwnProperty(key), which can throw or behave incorrectly for objects that override hasOwnProperty. Prefer Object.prototype.hasOwnProperty.call(obj, key) (or Object.hasOwn(obj, key) where supported).
| if (!obj.hasOwnProperty(key)) continue; | |
| if (!Object.prototype.hasOwnProperty.call(obj, key)) continue; |
| const encoded = Buffer.from( | ||
| `${p.auth.user}:${p.auth.password}` | ||
| ).toString("base64"); |
There was a problem hiding this comment.
generateJsFetch base64-encodes Basic Auth using Buffer.from(...), but this tool is a client component and Buffer is not available in the browser by default. Any cURL with -u/--user will throw during code generation. Use a browser-safe base64 encoding approach (e.g., btoa) or avoid encoding at generation time (emit code that encodes at runtime).
| const encoded = Buffer.from( | |
| `${p.auth.user}:${p.auth.password}` | |
| ).toString("base64"); | |
| const encoded = btoa(`${p.auth.user}:${p.auth.password}`); |
Converted all development tool components from static imports to next/dynamic imports to enable code splitting and reduce initial bundle size.
Changes :
Replaced static imports with dynamic imports ({ ssr: false })
Refactored developmentToolsRoutes to store component references instead of JSX
Updated [slug]/page.tsx to render dynamic components
Removed redundant individual tool pages
Added proper TypeScript typing (ComponentType)
Fixes #48