Skip to content

Commit

Permalink
refactor: use TS
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Apr 20, 2020
1 parent bfb4b91 commit 91d76bf
Show file tree
Hide file tree
Showing 18 changed files with 1,331 additions and 96 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.DS_Store
node_modules
dist
TODOs.md
playground
*.log
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2019-present, Yuxi (Evan) You

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
2 changes: 1 addition & 1 deletion bin/vds.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env node
const { createServer } = require('../lib/server')
const { createServer } = require('../dist/server')

// TODO pass cli args
createServer()
25 changes: 0 additions & 25 deletions lib/utils.js

This file was deleted.

36 changes: 35 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
{
"name": "@vue/dev-server",
"version": "0.2.0",
"license": "MIT",
"author": "Evan You",
"bin": {
"vds": "bin/vds.js"
},
"main": "lib/server.js",
"main": "dist/server/index.js",
"types": "dist/server/index.d.ts",
"scripts": {
"dev": "run-p dev-client dev-server",
"dev-client": "tsc -w --p src/client",
"dev-server": "tsc -w --p src/server",
"build": "tsc -p src/client && tsc -p src/server",
"lint": "prettier --write --parser typescript \"src/**/*.ts\"",
"prepublishOnly": "tsc"
},
"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"*.js": [
"prettier --write",
"git add"
],
"*.ts": [
"prettier --parser=typescript --write",
"git add"
]
},
"dependencies": {
"@babel/parser": "^7.9.4",
"@vue/compiler-sfc": "^3.0.0-beta.2",
Expand All @@ -14,5 +38,15 @@
"serve-handler": "^6.1.2",
"vue": "^3.0.0-beta.3",
"ws": "^7.2.3"
},
"devDependencies": {
"@types/node": "^13.13.1",
"@types/serve-handler": "^6.1.0",
"@types/ws": "^7.2.4",
"lint-staged": "^10.1.6",
"npm-run-all": "^4.1.5",
"prettier": "^2.0.4",
"typescript": "^3.8.3",
"yorkie": "^2.0.0"
}
}
9 changes: 6 additions & 3 deletions lib/hmrClient.js → src/client/client.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
// This file runs in the browser.
import { HMRRuntime } from 'vue'

declare var __VUE_HMR_RUNTIME__: HMRRuntime

const socket = new WebSocket(`ws://${location.host}`)

Expand All @@ -10,19 +13,19 @@ socket.addEventListener('message', ({ data }) => {
console.log(`[vds] connected.`)
break
case 'reload':
import(`${path}?t=${Date.now()}`).then(m => {
import(`${path}?t=${Date.now()}`).then((m) => {
__VUE_HMR_RUNTIME__.reload(path, m.default)
console.log(`[vds] ${path} reloaded.`)
})
break
case 'rerender':
import(`${path}?type=template&t=${Date.now()}`).then(m => {
import(`${path}?type=template&t=${Date.now()}`).then((m) => {
__VUE_HMR_RUNTIME__.rerender(path, m.render)
console.log(`[vds] ${path} template updated.`)
})
break
case 'update-style':
import(`${path}?type=style&index=${index}&t=${Date.now()}`).then(m => {
import(`${path}?type=style&index=${index}&t=${Date.now()}`).then((m) => {
// TODO style hmr
})
break
Expand Down
10 changes: 10 additions & 0 deletions src/client/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": ".",
"outDir": "../../dist/client",
"module": "esnext",
"lib": ["ESNext", "DOM"]
},
"include": ["./"]
}
16 changes: 11 additions & 5 deletions lib/hmrWatcher.js → src/server/hmrWatcher.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
const fs = require('fs')
const path = require('path')
const chokidar = require('chokidar')
const { parseSFC } = require('./parseSFC')
import path from 'path'
import chokidar from 'chokidar'
import { parseSFC } from './parseSFC'

exports.createFileWatcher = (notify) => {
export interface ServerNotification {
type: string
path?: string
}

export function createFileWatcher(
notify: (payload: ServerNotification) => void
) {
const fileWatcher = chokidar.watch(process.cwd(), {
ignored: [/node_modules/]
})
Expand Down
1 change: 1 addition & 0 deletions src/server/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { createServer, ServerConfig } from './server'
16 changes: 8 additions & 8 deletions lib/moduleMiddleware.js → src/server/moduleMiddleware.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
const path = require('path')
const resolve = require('resolve-cwd')
const { sendJSStream } = require('./utils')
import path from 'path'
import resolve from 'resolve-cwd'
import { sendJSStream } from './utils'
import { ServerResponse } from 'http'

exports.moduleMiddleware = (id, res) => {
let modulePath
export function moduleMiddleware(id: string, res: ServerResponse) {
let modulePath: string
// TODO support custom imports map e.g. for snowpack web_modules

// fallback to node resolve
Expand All @@ -15,10 +16,9 @@ exports.moduleMiddleware = (id, res) => {
'dist/vue.runtime.esm-browser.js'
)
}
sendJSStream(res, modulePath)
} catch (e) {
res.setStatus(404)
res.statusCode = 404
res.end()
}

sendJSStream(res, modulePath)
}
26 changes: 13 additions & 13 deletions lib/moduleRewriter.js → src/server/moduleRewriter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const { parse } = require('@babel/parser')
const ms = require('magic-string')
import { parse } from '@babel/parser'
import MagicString from 'magic-string'

exports.rewrite = (source, asSFCScript = false) => {
export function rewrite(source: string, asSFCScript = false) {
const ast = parse(source, {
sourceType: 'module',
plugins: [
Expand All @@ -14,27 +14,27 @@ exports.rewrite = (source, asSFCScript = false) => {
]
}).program.body

let s
const s = new MagicString(source)
ast.forEach((node) => {
if (node.type === 'ImportDeclaration') {
if (/^[^\.\/]/.test(node.source.value)) {
// module import
// import { foo } from 'vue' --> import { foo } from '/__modules/vue'
;(s || (s = new ms(source))).overwrite(
node.source.start,
node.source.end,
s.overwrite(
node.source.start!,
node.source.end!,
`"/__modules/${node.source.value}"`
)
}
} else if (node.type === 'ExportDefaultDeclaration') {
;(s || (s = new ms(source))).overwrite(
node.start,
node.declaration.start,
} else if (asSFCScript && node.type === 'ExportDefaultDeclaration') {
s.overwrite(
node.start!,
node.declaration.start!,
`let __script; export default (__script = `
)
s.appendRight(node.end, `)`)
s.appendRight(node.end!, `)`)
}
})

return s ? s.toString() : source
return s.toString()
}
6 changes: 3 additions & 3 deletions lib/parseSFC.js → src/server/parseSFC.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const fs = require('fs').promises
const { parse } = require('@vue/compiler-sfc')
import { promises as fs } from 'fs'
import { parse } from '@vue/compiler-sfc'

const cache = new Map()

exports.parseSFC = async (filename, saveCache = false) => {
export async function parseSFC(filename: string, saveCache = false) {
const content = await fs.readFile(filename, 'utf-8')
const { descriptor, errors } = parse(content, {
filename
Expand Down
45 changes: 25 additions & 20 deletions lib/server.js → src/server/server.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
const fs = require('fs').promises
const path = require('path')
const http = require('http')
const url = require('url')
const ws = require('ws')
const serve = require('serve-handler')
const vue = require('./vueMiddleware')
const { moduleMiddleware } = require('./moduleMiddleware')
const { createFileWatcher } = require('./hmrWatcher')
const { sendJS } = require('./utils')
const { rewrite } = require('./moduleRewriter')
import { promises as fs } from 'fs'
import path from 'path'
import http from 'http'
import url from 'url'
import WebSocket from 'ws'
import serve from 'serve-handler'
import { vueMiddleware } from './vueMiddleware'
import { moduleMiddleware } from './moduleMiddleware'
import { createFileWatcher } from './hmrWatcher'
import { sendJS } from './utils'
import { rewrite } from './moduleRewriter'

exports.createServer = async ({ port = 3000 } = {}) => {
export interface ServerConfig {
port?: number
}

export async function createServer({ port = 3000 }: ServerConfig = {}) {
const hmrClientCode = await fs.readFile(
path.resolve(__dirname, './hmrClient.js')
path.resolve(__dirname, '../client/client.js')
)

const server = http.createServer(async (req, res) => {
const pathname = url.parse(req.url).pathname
const pathname = url.parse(req.url!).pathname!
if (pathname === '/__hmrClient') {
return sendJS(res, await hmrClientCode)
return sendJS(res, hmrClientCode)
} else if (pathname.startsWith('/__modules/')) {
return moduleMiddleware(pathname.replace('/__modules/', ''), res)
} else if (pathname.endsWith('.vue')) {
return vue(req, res)
return vueMiddleware(req, res)
} else if (pathname.endsWith('.js')) {
const filename = path.join(process.cwd(), pathname.slice(1))
try {
Expand All @@ -42,8 +46,8 @@ exports.createServer = async ({ port = 3000 } = {}) => {
})
})

const wss = new ws.Server({ server })
const sockets = new Set()
const wss = new WebSocket.Server({ server })
const sockets = new Set<WebSocket>()

wss.on('connection', (socket) => {
sockets.add(socket)
Expand All @@ -53,7 +57,7 @@ exports.createServer = async ({ port = 3000 } = {}) => {
})
})

wss.on('error', (e) => {
wss.on('error', (e: Error & { code: string }) => {
if (e.code !== 'EADDRINUSE') {
console.error(e)
}
Expand All @@ -64,7 +68,7 @@ exports.createServer = async ({ port = 3000 } = {}) => {
)

return new Promise((resolve, reject) => {
server.on('error', (e) => {
server.on('error', (e: Error & { code: string }) => {
if (e.code === 'EADDRINUSE') {
console.log(`port ${port} is in use, trying another one...`)
setTimeout(() => {
Expand All @@ -73,6 +77,7 @@ exports.createServer = async ({ port = 3000 } = {}) => {
}, 100)
} else {
console.error(e)
reject(e)
}
})

Expand Down
10 changes: 10 additions & 0 deletions src/server/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": ".",
"outDir": "../../dist/server",
"module": "commonjs",
"lib": ["ESNext"]
},
"include": ["./"]
}
26 changes: 26 additions & 0 deletions src/server/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import fs from 'fs'
import { ServerResponse } from 'http'

export function send(
res: ServerResponse,
source: string | Buffer,
mime: string
) {
res.setHeader('Content-Type', mime)
res.end(source)
}

export function sendJS(res: ServerResponse, source: string | Buffer) {
send(res, source, 'application/javascript')
}

export function sendJSStream(res: ServerResponse, filename: string) {
res.setHeader('Content-Type', 'application/javascript')
const stream = fs.createReadStream(filename)
stream.on('open', () => {
stream.pipe(res)
})
stream.on('error', (err) => {
res.end(err)
})
}
Loading

0 comments on commit 91d76bf

Please sign in to comment.