AI 资讯
TanStack Start vs Nuxt: One Framework to rule them all?
I love Nuxt and I really like TanStack Start. But which one is better? Or are they about the same? And if they are about the same, does it do anything my Nuxt setup can't, and is that worth leaving Vue for React? So I decided to build the same app in both frameworks and take a look. Read on below to find out! If you'd rather watch a video, check out the video on the same topic! The app In both frameworks I built a small GitHub user lookup app. You type a username, the profile gets fetched on the server, and the username lands in the URL as a ?user= query param so the result is shareable. Type ErikCH , hit enter, and the card renders. Refresh the page and it's still there. It has the same behaviour so the difference lies in the code. Difference one: server functions vs server routes On the Nuxt side we call a server route from useAsyncData . Server are the more idiomatic way to use Nuxt to call things on the server. <!-- app/pages/index.vue --> < script setup lang= "ts" > import { z } from ' zod ' import type { GithubUser } from ' ~~/server/api/github.get ' definePageMeta ({ props : route => z . object ({ user : z . string (). default ( '' ) }). parse ( route . query ), }) const props = defineProps < { user : string } > () const router = useRouter () const input = ref ( props . user ) const { data , error } = await useAsyncData ( ' github-user ' , () => props . user ? $fetch < GithubUser > ( ' /api/github ' , { query : { user : props . user } }) : Promise . resolve ( null ), { watch : [() => props . user ] }, ) function lookup () { router . push ({ query : { user : input . value . trim () } }) } </ script > The props option on definePageMeta maps the query into a typed page prop and re-runs on client navigation. useAsyncData fetches when there's a username and refetches whenever it changes. The conditional that returns Promise.resolve(null) skips the request on an empty query param, (or when you first load). The server route does the outbound call: // server/api/gith
开发者
Nuxt In 2026: The Vue Full-Stack Framework That Deserves More Attention
Everyone knows Next.js is the default full-stack JavaScript framework in 2026. The job ads say so,...
AI 资讯
Stop Creating a React Project Just to Preview a JSX File
If you're using AI coding assistants like ChatGPT, Claude, Cursor, or Lovable, you've probably accumulated dozens of JSX components. Generating them is incredibly fast. Previewing them? Not so much. The Typical Workflow Every time I received a JSX component, I found myself repeating the same process. Create a React project (or open an existing one) Copy the JSX file Install dependencies Fix missing imports Run the development server Wait for everything to compile All of that... just to see one component. It felt like unnecessary overhead. There Had to Be a Better Way I asked myself a simple question: Why can't I just double-click a JSX file and preview it? We can instantly open images, PDFs, videos, and text files. Why should JSX files require an entire development environment? That's what inspired me to build PreviewKit . What is PreviewKit ? PreviewKit is a lightweight Windows application that lets you preview frontend components instantly. Supported file types include: ✅ JSX ✅ Vue ✅ HTML No project setup. No dependency installation. No terminal commands. Just open the file and see the result. Why I Built It AI has dramatically changed frontend development. We're no longer spending most of our time writing components—we're reviewing, comparing, and refining them. That means fast visual feedback is more important than ever. I wanted a tool that removed the repetitive setup process so I could focus on building better interfaces instead of preparing a preview environment. Who Is It For? PreviewKit is useful if you: Build React applications Work with Vue components Test standalone HTML files Generate UI with AI tools Review components from teammates Prototype interfaces quickly If opening frontend files feels slower than it should, PreviewKit was built for you. The Goal Isn't to Replace Your Framework You'll still use React. You'll still use Vue. You'll still use Vite or Next.js. PreviewKit isn't trying to replace your existing workflow. It simply removes one frustrat
AI 资讯
How I Split PDFs in the Browser with Vue 3 and pdf-lib
Splitting a PDF is one of those features that sounds trivial until you try to build it. Users expect range input ( 1-3, 5, 7-9 ), a per-page option, multiple file downloads, and zero server involvement. I built en.sotool.top/split/ to do exactly that. Here's how it works with Vue 3 and pdf-lib . Why Client-Side? PDFs often contain sensitive information. Contracts, medical records, financial statements. Even a "simple" splitting tool should not force users to upload files to a server. Client-side benefits: No upload bandwidth or size limits No server storage or cleanup Instant processing for normal files Works offline after the page loads The tradeoff is that everything has to run in the browser, which limits the libraries you can use. The Stack Vue 3 — UI and state pdf-lib — Load, manipulate, and save PDFs File API — Read the uploaded file lucide-vue-next — Icons npm install pdf-lib Loading the PDF and Counting Pages First, read the file into an ArrayBuffer and load it with pdf-lib . import { PDFDocument } from ' pdf-lib ' const pdfFile = ref < File | null > ( null ) const totalPages = ref ( 0 ) async function handleFile ( files : File []) { if ( files . length === 0 ) return pdfFile . value = files [ 0 ] const bytes = await files [ 0 ]. arrayBuffer () const pdf = await PDFDocument . load ( bytes ) totalPages . value = pdf . getPageCount () } Now we know how many pages exist and can show the split UI. Two Split Modes I offer two ways to split: by range and per page. Mode 1: Page Range Input Users type something like 1-3, 5, 7-9 . I parse it into groups of page indices. function parseRanges ( input : string , max : number ): number [][] { const groups : number [][] = [] const parts = input . split ( ' , ' ). map ( s => s . trim ()) for ( const part of parts ) { if ( part . includes ( ' - ' )) { const [ start , end ] = part . split ( ' - ' ). map ( Number ) const pages = [] for ( let i = start ; i <= end && i <= max ; i ++ ) { pages . push ( i - 1 ) } if ( pages . len
AI 资讯
How to Convert Word to PDF in the Browser with Vue 3, mammoth, and html2pdf.js
Converting Word documents to PDFs on the server is the classic approach: upload the file, run LibreOffice or a cloud API, send the result back. But that means your users’ resumes, contracts, and reports touch your infrastructure. I wanted something simpler for en.sotool.top : pick a .docx file in the browser, preview the parsed content, and download a PDF. No server involved. Here is how I built it with Vue 3, mammoth , and html2pdf.js . Why Client-Side? The main reason is privacy. Resumes, contracts, tax documents — users do not want them on a stranger’s server. Client-side conversion also means: No upload bandwidth limits No file size caps from your server No storage to clean up Works offline after the page loads The trade-off is that very complex documents are limited by the browser’s rendering capabilities. For typical office documents, that is fine. The Stack Vue 3 — UI, file handling, and reactive state mammoth — Parse .docx files into clean HTML html2pdf.js — Render the HTML into a PDF using html2canvas + jsPDF Native File API — File selection npm install mammoth html2pdf.js Loading the Word Document The first step is reading the uploaded .docx file into an ArrayBuffer , then converting it to HTML with mammoth . import mammoth from ' mammoth ' ; async function convertDocxToHtml ( file ) { const arrayBuffer = await file . arrayBuffer (); const result = await mammoth . convertToHtml ({ arrayBuffer }); return result . value ; } mammoth intentionally produces simple, clean HTML. It ignores complex formatting like text boxes and embedded fonts, which makes the output predictable. I keep the HTML in a reactive ref and render it in a preview panel: < template > <div ref= "previewRef" class= "word-preview" v-html= "htmlContent" ></div> </ template > < script setup > import { ref } from ' vue ' ; const htmlContent = ref ( '' ); const previewRef = ref ( null ); </ script > Generating the PDF Once the user is happy with the preview, html2pdf.js turns the preview element
AI 资讯
State-Driven Animations in Vue: Create Smooth UI Transitions with Reactive State
Animations can make an application feel faster, smoother, and more polished. However, many developers think animations are only useful for things like: page transitions modals enter/leave effects But Vue provides another powerful pattern - State-driven animations. Instead of animating when elements are added or removed from the DOM, you animate changes in reactive state. This allows you to create rich interactive experiences while keeping your code declarative and easy to maintain. In this article, we'll explore: What state-driven animations are How they differ from regular Vue transitions What problems they solve How to implement them in Vue Best practices for creating smooth UI interactions Let's dive in. 🤔 What Are State-Driven Animations? Most Vue developers are familiar with the <Transition> component. Example: <Transition> <Modal v-if= "isOpen" /> </Transition> This animates an element when it enters or leaves the DOM. But what if the element already exists and only its state changes? For example: a progress bar grows a card expands a chart updates a panel changes size a value changes position This is where state-driven animations shine. Instead of animating DOM insertion or removal, you animate changes caused by reactive state. 🟢 What Problem Do State-Driven Animations Solve? Without animations, state changes can feel abrupt. Example: <div :style= "{ width: progress + '%' }" ></div> When progress changes: progress . value = 80 The width instantly jumps. This works technically... but it doesn't feel great. 🟢 A Simple Example Let's create an animated progress bar. < script setup lang= "ts" > const progress = ref ( 20 ) function increase () { progress . value += 20 } </ script > < template > <button @ click= "increase" > Increase Progress </button> <div class= "progress-container" > <div class= "progress-bar" :style= " { width: `${progress}%` }" /> </div> </ template > CSS: .progress-container { width : 100% ; height : 12px ; background : #eee ; } .progress-bar