├── devServer.js ├── .gitignore ├── index.js ├── package.json ├── src ├── state.js ├── runtime.vue └── parse.js └── readme.md /devServer.js: -------------------------------------------------------------------------------- 1 | const { setActive } = require('./src/state') 2 | module.exports = function (app, server, compiler) { 3 | app.get('/start', function (req, res) { 4 | const name = req.query.name 5 | res.send('') 6 | setActive(name) 7 | }) 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const { init, getVersionFilePath } = require('./src/state') 2 | const { parse, unParse } = require('./src/parse') 3 | module.exports = function (source, map) { 4 | init() 5 | const loaderContext = this 6 | const { 7 | resourcePath, 8 | resourceQuery 9 | } = loaderContext 10 | 11 | loaderContext.addDependency(getVersionFilePath()) 12 | const ast = parse(source) 13 | const s = unParse(ast, { resourcePath }) 14 | 15 | return s 16 | } 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-fast-dev-server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/iptop/vue-fast-dev-server.git" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/iptop/vue-fast-dev-server/issues" 17 | }, 18 | "homepage": "https://github.com/iptop/vue-fast-dev-server#readme" 19 | } 20 | -------------------------------------------------------------------------------- /src/state.js: -------------------------------------------------------------------------------- 1 | let isInit = false 2 | let version = 0 3 | const path = require('path') 4 | const fs = require('fs') 5 | const activeRoutes = {} 6 | function getVersionFilePath () { 7 | return path.join(process.cwd(), 'node_modules', 'lazy-route-loader-version') 8 | } 9 | 10 | function setVersion () { 11 | version++ 12 | const fileName = getVersionFilePath() 13 | fs.writeFileSync(fileName, version.toString()) 14 | } 15 | 16 | function init () { 17 | if (isInit) { 18 | return 19 | } 20 | isInit = true 21 | setVersion() 22 | } 23 | 24 | function getRuntimePath () { 25 | return path.join(require.resolve('./runtime.vue')) 26 | } 27 | 28 | function setActive (name) { 29 | if (activeRoutes[name]) { 30 | 31 | } else { 32 | activeRoutes[name] = true 33 | setVersion() 34 | } 35 | } 36 | 37 | function getActiveRoute () { 38 | return activeRoutes 39 | } 40 | 41 | module.exports = { 42 | init, 43 | getVersionFilePath, 44 | getRuntimePath, 45 | setActive, 46 | getActiveRoute 47 | } 48 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # vue-fast-dev-server 2 | 3 | > 10倍缩短您的vue dev server启动时间 4 | 5 | ![avatar](https://github.com/iptop/vue-fast-dev-server-demo/blob/master/src/assets/demo.gif?raw=true) 6 | ## 安装 7 | 8 | ``` bash 9 | npm install vue-fast-dev-server --save-dev 10 | ``` 11 | vue.config.js 12 | 13 | ``` js 14 | const path = require('path') 15 | 16 | module.exports = { 17 | devServer: { 18 | before: require('vue-fast-dev-server/devServer') 19 | }, 20 | configureWebpack: config => { 21 | config.module.rules.push({ 22 | test: /\.js$/, 23 | include: [ 24 | path.resolve(__dirname, 'src/router/modules') 25 | ], 26 | loader: 'vue-fast-dev-server' 27 | }) 28 | } 29 | } 30 | 31 | ``` 32 | 请把你的路由定义文件迁移至src/router/modules目录下 33 | 34 | 参考 [iptop/vue-fast-dev-server-demo](https://github.com/iptop/vue-fast-dev-server-demo). 35 | 36 | ## 原理 37 | 38 | > 让浏览器和 dev server 进行联动,没有访问到的路由就直接跳过编译,不管多大的项目都是秒开 39 | 40 | ## 性能提升 41 | 42 | 43 | | 项目 | 加速前 | 加速后| 44 | | --------------------------- | ----------|------| 45 | | dev server 启动时间(带缓存) | 80S | 2S | 46 | | dev server 内存占用 |1600MB |200MB | 47 | | HRM响应速度 | 7.7S | 0.3S| 48 | -------------------------------------------------------------------------------- /src/runtime.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 24 | 25 | 87 | -------------------------------------------------------------------------------- /src/parse.js: -------------------------------------------------------------------------------- 1 | const { getRuntimePath, getActiveRoute } = require('./state') 2 | function parse (source) { 3 | const reg = new RegExp('{[\\d\\D]*?component[\\d\\D]*?import[\\d\\D]*?}', 'g') 4 | const length = source.length 5 | let lastIndex = 0 6 | const ast = [] 7 | 8 | function extractStaticText (s, e) { 9 | const staticText = source.substr(s, e - s) 10 | ast.push({ 11 | type: 'static', 12 | raw: staticText 13 | }) 14 | } 15 | 16 | function extractRoute (s) { 17 | ast.push({ 18 | type: 'route', 19 | raw: s 20 | }) 21 | } 22 | 23 | while (true) { 24 | const nrt = reg.exec(source) 25 | if (nrt) { 26 | const s = nrt[0] 27 | const is = nrt.index 28 | extractStaticText(lastIndex, is) 29 | extractRoute(s) 30 | const l = s.length 31 | lastIndex = is + l 32 | } else { 33 | extractStaticText(lastIndex, length) 34 | break 35 | } 36 | } 37 | 38 | return ast 39 | } 40 | 41 | function getRouteName (s) { 42 | const reg = new RegExp("name: \\'(.*?)\\'", 'g') 43 | const rt = reg.exec(s) 44 | if (rt) { 45 | return rt[1] 46 | } else { 47 | return '' 48 | } 49 | } 50 | 51 | function unParse (ast, { resourcePath }) { 52 | let str = '' 53 | for (const s of ast) { 54 | switch (s.type) { 55 | case 'static': 56 | str += s.raw 57 | break 58 | case 'route': 59 | const routerName = getRouteName(s.raw) 60 | 61 | const activeRoute = getActiveRoute() 62 | 63 | if (activeRoute[routerName]) { 64 | str += s.raw 65 | } else { 66 | const reg = new RegExp('(component[\\d\\D]*?import\\().*?(\\))', 'g') 67 | const np = getRuntimePath().replace(new RegExp('\\\\', 'g'), '/') 68 | const ns = s.raw.replace(reg, `$1 '${np}' $2`) 69 | str += ns 70 | } 71 | 72 | break 73 | } 74 | } 75 | return str 76 | } 77 | 78 | module.exports = { 79 | parse, 80 | unParse 81 | } 82 | --------------------------------------------------------------------------------