├── .gitignore ├── README.md ├── components ├── head.js └── nav.js ├── next.config.js ├── package.json ├── pages ├── admin │ ├── index.js │ └── sample-page.js └── member │ ├── accounts │ └── dashboard.js │ └── index.js ├── server.js ├── static └── favicon.ico └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | /dist 12 | /.next 13 | 14 | # misc 15 | .DS_Store 16 | .env 17 | npm-debug.log* 18 | yarn-debug.log* 19 | yarn-error.log* 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Next.js Subdomain Example 2 | 3 | ## It uses the following as references: 4 | * https://nextjs.org/docs/advanced-features/custom-server 5 | * https://github.com/vercel/next.js/tree/canary/examples/custom-server-express 6 | * https://stackoverflow.com/a/50052939/9375533 7 | 8 | ## If we are going to run this using `next dev` we will have the following routes: 9 | * http://lvh.me:3000/admin 10 | * http://lvh.me:3000/admin/sample-page 11 | * http://lvh.me:3000/member 12 | * http://lvh.me:3000/member/accounts/dashboard 13 | 14 | ## But by running `node server.js` we will have the following routes: 15 | * http://admin.lvh.me:3000 16 | * http://admin.lvh.me:3000/sample-page 17 | * http://lvh.me:3000 18 | * http://lvh.me:3000/accounts/dashboard 19 | 20 | ## Development Setup 21 | * `git clone https://github.com/dcangulo/nextjs-subdomain-example.git` 22 | * `cd nextjs-subdomain-example` 23 | * `yarn` 24 | * `yarn dev` 25 | -------------------------------------------------------------------------------- /components/head.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import NextHead from 'next/head' 3 | import { string } from 'prop-types' 4 | 5 | const defaultDescription = '' 6 | const defaultOGURL = '' 7 | const defaultOGImage = '' 8 | 9 | const Head = props => ( 10 | 11 | 12 | {props.title || ''} 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ) 36 | 37 | Head.propTypes = { 38 | title: string, 39 | description: string, 40 | url: string, 41 | ogImage: string 42 | } 43 | 44 | export default Head 45 | -------------------------------------------------------------------------------- /components/nav.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Link from 'next/link' 3 | 4 | const links = [ 5 | { href: 'https://github.com/segmentio/create-next-app', label: 'Github' } 6 | ].map(link => { 7 | link.key = `nav-link-${link.href}-${link.label}` 8 | return link 9 | }) 10 | 11 | const Nav = () => ( 12 | 57 | ) 58 | 59 | export default Nav 60 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | webpack: config => { 3 | // Fixes npm packages that depend on `fs` module 4 | config.node = { 5 | fs: 'empty' 6 | } 7 | 8 | return config 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-next-example-app", 3 | "scripts": { 4 | "dev": "node server.js", 5 | "build": "next build", 6 | "start": "NODE_ENV=production node server.js" 7 | }, 8 | "dependencies": { 9 | "express": "^4.17.1", 10 | "next": "^9.5.2", 11 | "react": "^16.13.1", 12 | "react-dom": "^16.13.1", 13 | "vhost": "^3.0.2" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /pages/admin/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default function Admin() { 4 | return
Admin
5 | } 6 | -------------------------------------------------------------------------------- /pages/admin/sample-page.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default function SamplePage() { 4 | return
SamplePage
5 | } 6 | -------------------------------------------------------------------------------- /pages/member/accounts/dashboard.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default function MemberDashboard() { 4 | return
MEMBER DASHBOARD
5 | } 6 | -------------------------------------------------------------------------------- /pages/member/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default function Member() { 4 | return
Member
5 | } 6 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const next = require('next') 3 | const vhost = require('vhost') 4 | 5 | const port = process.env.PORT || 3000 6 | const dev = process.env.NODE_ENV !== 'production' 7 | const app = next({ dev }) 8 | const handle = app.getRequestHandler() 9 | 10 | app.prepare().then(() => { 11 | const mainServer = express() 12 | const adminServer = express() 13 | const memberServer = express() 14 | 15 | adminServer.get('/', (req, res) => { 16 | return app.render(req, res, '/admin', req.query) 17 | }) 18 | 19 | adminServer.get('/*', (req, res) => { 20 | return app.render(req, res, `/admin${req.path}`, req.query) 21 | }) 22 | 23 | adminServer.all('*', (req, res) => { 24 | return handle(req, res) 25 | }) 26 | 27 | memberServer.get('/', (req, res) => { 28 | return app.render(req, res, '/member', req.query) 29 | }) 30 | 31 | memberServer.get('/*', (req, res) => { 32 | return app.render(req, res, `/member${req.path}`, req.query) 33 | }) 34 | 35 | memberServer.all('*', (req, res) => { 36 | return handle(req, res) 37 | }) 38 | 39 | mainServer.use(vhost('admin.lvh.me', adminServer)) 40 | mainServer.use(vhost('lvh.me', memberServer)) 41 | mainServer.use(vhost('www.lvh.me', memberServer)) 42 | mainServer.listen(port, (err) => { 43 | if (err) throw err 44 | 45 | console.log(`> Ready on http://lvh.me:${port}`) 46 | }) 47 | }) 48 | -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcangulo/nextjs-subdomain-example/f3cba73d51dbd3349ba10008565049adbee3529e/static/favicon.ico --------------------------------------------------------------------------------