Skip to content

Instantly share code, notes, and snippets.

@ShaggyTech
Last active March 12, 2022 16:09
Show Gist options
  • Select an option

  • Save ShaggyTech/c0004583618a09bc145c1a6c6b845207 to your computer and use it in GitHub Desktop.

Select an option

Save ShaggyTech/c0004583618a09bc145c1a6c6b845207 to your computer and use it in GitHub Desktop.
Setup files needed for Nuxt TypeScript Runtime - working hot module reloading, automatic browser updates
// ./server/index.ts
// Add or remove watched FOLDER_NAMES or FILE_EXTENSIONS as desired
export { NuxtServer } from './NuxtServer'
export const PORT = 3000
export const FOLDER_NAMES = `
assets
|components
|compositions
|layouts
|middleware
|pages
|plugins
|server
|static
|store
|types
|utils
`
export const FILE_EXTENSIONS = 'js,ts,jsx,vue'
export const WATCH_GLOB = `./+(${FOLDER_NAMES})/**/*.{${FILE_EXTENSIONS}}`
// ./types/nuxt-shim-d.ts
declare module 'nuxt-edge' {
const Nuxt: any
const Builder: any
export { Nuxt, Builder }
}
// ./nuxt-config.ts
import { Configuration } from '@nuxt/types'
import { name, description } from './package.json'
const isDev: boolean = process.env.NODE_ENV !== 'production'
const config: Configuration = {
dev: isDev,
head: {
titleTemplate: '%s - ',
title: name || '',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{
hid: name || '',
name: name || '',
content: description || ''
}
]
},
buildModules: ['@nuxt/typescript-build']
// See https://typescript.nuxtjs.org/guide/setup.html#type-check
// uncomment below to use it
// typescript: {
// typeCheck: {
// eslint: true
// }
// }
}
export default config
// ./server/NuxtServer.ts
import express from 'express'
import consola from 'consola'
import { Nuxt, Builder } from 'nuxt-edge'
import config from '../nuxt.config'
import { PORT } from './'
export class NuxtServer {
// Note: Nuxt is still stubbed out, are there corresponding nuxt types?
app: any;
host: any;
nuxt: any;
port: number;
started: boolean;
constructor (port?: number) {
this.app = express()
this.nuxt = new Nuxt(config)
this.host = this.nuxt.options.server.host
this.port = port || PORT
this.started = false
}
async buildNuxt () {
const builder = new Builder(this.nuxt)
await builder.build()
}
async start () {
await this.nuxt.ready()
// NOTE: remove "!this.started || " if you want to skip building one time on production start
// Build once in production and every time in dev mode if this.start() is called
if (!this.started || config.dev) {
await this.buildNuxt()
}
// Start the server one time only
if (!this.started) {
// Give nuxt middleware to express
this.app.use(this.nuxt.render)
// Listen to the server
this.app.listen(this.port, this.host)
// flag that the server is already running
this.started = true
consola.ready({
message: `Server listening on http://${this.host}:${this.port}`,
badge: true
})
}
}
}
{
"scripts": {
"dev": "ts-node --project server/tsconfig.json server/server-dev.ts",
"build": "nuxt-ts build",
"start": "cross-env NODE_ENV=production ts-node --project 'server/tsconfig.json' server/server-prod.ts",
"generate": "nuxt-ts generate"
},
"dependencies": {
"@nuxt/typescript-runtime": "latest",
"cross-env": "latest",
"nuxt-edge": "latest"
},
"devDependencies": {
"@nuxt/typescript-build": "latest",
"express": "latest"
}
}
// ./server/server-dev.ts
// Development Server with HMR and folder/file watching
// Use with 'yarn dev' command
import chokidar from 'chokidar'
import consola from 'consola'
import { NuxtServer, WATCH_GLOB } from '.'
const server = new NuxtServer()
consola.start({
message: `Starting Nuxt HMR dev server on http://${server.host}:${server.port}`,
badge: true
})
server.start()
chokidar.watch([WATCH_GLOB], {
ignoreInitial: true
}).on('change', () => {
server.buildNuxt()
})
// ./server/server-prod.ts
// Production server
// By default, it will perform a one time build and then start the production server
// For info on how to skip the one time production build: see NOTE on line 36 of 'NuxtServer.ts'
// Use with 'yarn start' command
import consola from 'consola'
import { NuxtServer } from '.'
const startProduction = () => {
const server = new NuxtServer()
consola.start({
message: `Starting production server on http://${server.host}:${server.port}`,
badge: true
})
server.start()
}
export default startProduction()
// REMOVE THESE COMMENTS!!!!
//
// ./server/tsconfig.json
//
// REMOVE THESE COMMENTS!!!!
{
"extends": "../tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"baseUrl": ".",
"paths": {
"nuxt-edge": ["../types/nuxt-shim"]
}
}
}
// ./types/vue-shim-d.ts
declare module '*.vue' {
import Vue from 'vue'
export default Vue
}
@ShaggyTech
Copy link
Author

I created a gist with all of the setup files needed to use Nuxt typescript runtime with a HMR development server and one-time-build production server. The dev server does not need to restart itself after changes, so the browser will stay connected. This means during development, browser changes appear more quickly and for the most part you won't need to refresh the browser with every change. Live style changes during development were lighting fast for me in my limited testing.

There are still some scenarios where you will need to reload the browser. For instance, deleting an entire <style></style> tag from a .vue file will not remove those styles from the browser during hot module replacement, you'd need to do a browser refresh for them to show. The same goes for any setup files in composition api functions. For example, after initial build with the server already running, you add a console.log() statement to a function that is only called during component setup(). Saving the file will trigger a rebuild but the function located inside the setup() function will never run again and no logs will be consoled until you do a browser refresh.


File Locations

The file locations are listed in the first comment of each file, relative to your project root directory. Make sure to remove the comments from the .json files as they are invalid JSON.


Build and Start HMR Development:

yarn dev

Build Production once and start production server.

yarn start

See the NOTE comment in NuxtServer.ts for what code to edit if you wish to remove the one time production build feature.


See this codesandbox for a working example that uses the Vue composition api plugin.

Cheers 🍻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment