├── .gitignore ├── LICENSE ├── README.md ├── deepFind.js ├── index.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | unpackage/ 4 | dist/ 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 | 15 | # Editor directories and files 16 | .project 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw* 24 | /subModeConfig.js 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 天堂里的花大咩 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # uni-pages-hot-modules 2 | ## uni-app的pages.json的模块化及模块热重载 3 | 解决uni-app的pages.json无法模块化的问题,并且解决模块热重载和缓存的问题 4 | 5 | ### 安装 6 | ``` 7 | npm i uni-pages-hot-modules -S 8 | ``` 9 | [uni-app vite版本(vue3)示例项目](https://github.com/devilwjp/uni-pages-hot-modules-vite-demo) 10 | [uni-app webpack版本(vue2)示例项目](https://github.com/devilwjp/uni-pages-hot-modules-demo) 11 | 12 | 13 | # uniapp 版本分界线说明 14 | ## vue3 vite版本 使用说明 15 | uniapp vue3 vite版本已不再默认支持pages.js的钩子,所以uni-pages-hot-modules的使用方式转变为直接在pages.json中通过特殊的`条件编译`命令插入js入口,一种非常cool的使用方式! 16 | ```json 17 | { 18 | "pages": /* #exec hotJs('./page_modules/index.js') */, 19 | "subPackages": /* #exec hotJs('./subpackage_modules/index.js') */, 20 | "globalStyle": { 21 | "navigationBarTextStyle": "black", 22 | "navigationBarTitleText": "uni-app", 23 | "navigationBarBackgroundColor": "#F8F8F8", 24 | "backgroundColor": "#F8F8F8" 25 | } 26 | } 27 | ``` 28 | 或者直接将整个pages.json都托管到一个js中,比如托管给pages.js,**那么直接将整个pages.json的内容设置成如下的一行注释即可** 29 | ```json 30 | // #exec hotJs('./pages.js') 31 | ``` 32 | 然后在pages.json相同的路径下建立`pages.js` 33 | ```js 34 | // /src/pages.js 35 | module.exports = { 36 | pages: require('./page_modules/index.js'), 37 | subPackages: require('./subpackage_modules/index.js'), 38 | globalStyle: { 39 | navigationBarTextStyle: 'black', 40 | navigationBarTitleText: 'uni-app', 41 | navigationBarBackgroundColor: '#F8F8F8', 42 | backgroundColor: '#F8F8F8' 43 | } 44 | } 45 | ``` 46 | ### 注意! 47 | 所有插入pages.json的js(包括这些js依赖的其他js)都必须是commonJs规范 48 | 适用于uniapp vue3 vite版本的uni-pages-hot-modules版本要求>=1.0.0 49 | 所有插入pages.json的js(包括这些js依赖的其他js)**不支持**uniapp的条件编译,替代方案是直接通过js判断uniapp的条件编译变量 50 | #### 如何获取uniapp的条件编译变量 51 | ```js 52 | // /src/pages.js 53 | // 获取uniapp的条件编译环境变量 54 | const uniContext = require('@dcloudio/uni-cli-shared/dist/preprocess/context').getPreVueContext() 55 | module.exports = { 56 | pages: require('./page_modules/index.js'), 57 | subPackages: require('./subpackage_modules/index.js'), 58 | globalStyle: { 59 | navigationBarTextStyle: 'black', 60 | // 判断是否是H5环境 61 | navigationBarTitleText: uniContext.H5 ? 'H5环境' : '非H5环境', 62 | navigationBarBackgroundColor: '#F8F8F8', 63 | // 判断是否是微信小程序环境 64 | backgroundColor: '#F8F8F8' 65 | } 66 | } 67 | ``` 68 | ### 前置配置 69 | 要使pages.json中可以使用特殊的条件编译命令,需要配置项目根目录中的`vite.config.js` 70 | ```js 71 | // vite.config.js 72 | import { defineConfig } from 'vite' 73 | import uni from '@dcloudio/vite-plugin-uni' 74 | 75 | // 引入uni-pages-hot-modules 76 | import uniHot from 'uni-pages-hot-modules' 77 | // 安装条件编译命令,安装之后,uniapp就会支持exec hotJs的条件编译 78 | uniHot.setupHotJs() 79 | // 也可以自定义条件编译的方法名 80 | // 以下执行的结果,在条件编译中将变成exec customJsFun 81 | // uniHot.setupHotJs('customJsFun') 82 | 83 | // https://vitejs.dev/config/ 84 | export default defineConfig({ 85 | plugins: [ 86 | uni(), 87 | // 注册uni-pages-hot-modules的热更新vite插件 88 | uniHot.createHotVitePlugin(), 89 | ], 90 | }) 91 | ``` 92 | ### API 93 | #### hotJs (通过条件编译使用在pages.json中,也可以自定义名称) 94 | uniapp的条件编译是借鉴`preprocess`插件,因此具备`#exec`命令 95 | hotJs引入的js的`module.exports`的结果将通过`JSON.stringify`直接呈现在pages.json中 96 | 使用前提条件,必须在`vite.config.js`中配置完成`setupHotJs`和`createHotVitePlugin` 97 | ```js 98 | // 在pages.json中可使用 99 | /* #exec hotJs('./other.js') */ 100 | // #exec hotJs('./other.js') 101 | ``` 102 | #### require.context (在pages.json依赖的js中使用,见vue2 webpack版本的说明) 103 | 模拟webpack的require.context,读取指定路径下符合条件的所有文件 104 | ___ 105 | ## vue2 webpack版本 使用说明 106 | ### 注意! 107 | + 发现uni-app每次更新对pages.js的支持度会不同,比如某个版本竟然注释掉了对pages.js的热重载依赖,这里做了兼容。只要uni-app不推翻自己的设计,此功能长久有效 108 | + 使用uni-pages-hot-modules引入模块必须输入全的文件名包括后缀,否则将不会进行热重载 109 | 110 | ### uni-pages-hot-modules做了什么 111 | ```javascript 112 | // 做了非常轻便的事情,相当于 113 | loader.addDependency(modulePath) 114 | delete require.cache[modulePath] 115 | require(modulePath) 116 | ``` 117 | 118 | ### uni-app的“彩蛋” 119 | uni-app自带一个webpack loader钩子文件pages.js,在项目src目录下建立pages.js(与pages.json同级)即可生效(pages.json仍然需要存在,作为初始值,建议存放一些和路由无关的配置)。 120 | pages.js要求CommonJS规范,直接通过module.exports输出一个钩子函数。 121 | 122 | ### pages.js输出的函数参数 123 | #### pagesJson < Object > 124 | pages.json的解析内容 125 | #### loader < Object > (无需关心) 126 | uni-pages-loader的钩子属性,{ addDependency < Function > } 127 | ##### addDependency (无需关心) 128 | 用于手动为uni-pages-loader添加依赖模块 129 | 130 | ### pages.js的模块化 131 | 由于是js,就可以实现模块的依赖,**如果不考虑模块的热重载问题,可以不使用hot高阶函数** 132 | 但是大多数情况下,需要依赖的模块也可以通过热重载更新pages.js,由于不是webpack的标准运行依赖,所以需要手动添加依赖项(使用addDependency),并且需要每次清除模块的缓存,因此uni-pages-hot-modules就诞生了 133 | 134 | ### pages.js示例 135 | ```javascript 136 | const { hot } = require('uni-pages-hot-modules') 137 | module.exports = hot((pagesJson) => { 138 | let basePages = [] 139 | let baseSubPackages = [] 140 | 141 | return { 142 | // 合并pages.json的内容 143 | ...pagesJson, 144 | pages:[ 145 | ...basePages, 146 | ...require('./page_modules/tabbar.js'), 147 | ...require('./page_modules/component.js'), 148 | ...require('./page_modules/appPlus.js'), 149 | ...require('./page_modules/module1.js') 150 | ], 151 | subPackages:[ 152 | ...baseSubPackages, 153 | ...require('./subpackage_modules/api.js'), 154 | ...require('./subpackage_modules/extUI.js'), 155 | ...require('./subpackage_modules/template.js') 156 | ] 157 | } 158 | }) 159 | 160 | 161 | ``` 162 | ### 模块的规范 163 | 被加载的模块也是CommonJS规范,通过module.exports输出 164 | #### module1.js示例 165 | ```javascript 166 | module.exports=[ 167 | { 168 | "path": "pages/sub/sub", 169 | "style": { 170 | "navigationBarTitleText": "sub" 171 | } 172 | }, 173 | // 在模块里继续引入其他子模块 174 | ...require('./some-sub-module1.js') 175 | ] 176 | ``` 177 | 178 | ### API 179 | #### context {function} 180 | 模拟webpack的require.context 181 | 与webpack不同的地方是不会将调用此方法的模块输出,没有id属性,resolve方法返回绝对路径 182 | ```javascript 183 | const files = require.context('.', true, /\.js$/) 184 | const modules = [] 185 | files.keys().forEach(key => { 186 | if (key === './index.js') return 187 | const item = files(key) 188 | modules.push(...item) 189 | }) 190 | module.exports = modules 191 | ``` 192 | 缺陷:require.context是模拟的,所以在支持热更新时也有一定缺陷,就是新创建的文件不支持热更新,需要重新编译即可(或者手动触发一次调用require.context的文件的更新也可以达到对新文件的热更新激活),删除和修改原有文件可以很好的支持热更新 193 | 194 | ### 其他 195 | 不支持条件编译,需要自己通过process.env.VUE_APP_PLATFORM来判断(不建议使用process.env.UNI_PLATFORM,因为在webpack客户端包里无法读取此环境变量,除非设置DefinePlugin),自定义环境的需要自己添加env变量来判断 196 | -------------------------------------------------------------------------------- /deepFind.js: -------------------------------------------------------------------------------- 1 | function deepFind (first, getChildren = () => {}, todo = () => {}) { 2 | if (todo(first) === false) { 3 | return 4 | } 5 | const children = getChildren(first) 6 | if (children) { 7 | children.forEach(child => deepFind(child, getChildren, todo)) 8 | } 9 | } 10 | 11 | module.exports = deepFind 12 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Vue2 webpack下使用 3 | * 在webpack的客户端包中如果要引入pages.js的相关依赖(pages.js文件本身不能被webpack的客户端包依赖) 4 | * 可以在pages.js中使用global引入uni-pages-hot-modules 5 | * 比如 global.hotRequire = require('uni-pages-hot-modules') 6 | * 这样pages.js的相关依赖中就不需要再定义hotRequire 7 | * 在vue.config.js中使用DefinePlugin将hotRequire和hotRequire.context分别替换成require和require.context 8 | * 在uni-app的应用中就可以引入pages.js的相关依赖模块了。比如可以直接用于uni-simple-router 9 | * 并且可以做到客户端包和本地配置包的双向热重载 10 | * 11 | * Vue3 vite下使用 12 | * 在pages.json中使用条件编译直接 #exec hotJs('./111.js') 13 | */ 14 | 15 | // 判断是否vue3和vite 16 | let Vue3 = false 17 | let getPreVueContext 18 | let handleHotUpdate 19 | const uniVue3HotPathList = new Set() 20 | const uniVue3HotDictList = new Set() 21 | let oldH5HotUpdate 22 | let h5Server 23 | let h5ServerUpdateLock 24 | function createGlobalPromise () { 25 | let resolve 26 | const lock = new Promise((r) => { 27 | resolve = r 28 | }) 29 | lock.resolve = resolve 30 | return lock 31 | } 32 | try { 33 | getPreVueContext = require('@dcloudio/uni-cli-shared/dist/preprocess/context').getPreVueContext() 34 | if (getPreVueContext.VUE3) { 35 | Vue3 = true 36 | } 37 | // 为vite版的uni-h5单独处理 38 | handleHotUpdate = require('@dcloudio/uni-h5-vite/dist/plugin/handleHotUpdate') 39 | oldH5HotUpdate = handleHotUpdate.createHandleHotUpdate() 40 | 41 | // 这里骚操作一下,重写createHandleHotUpdate,拦截入参的file属性,强行加上.pages.json的后缀 42 | // 因为uni vite本身判断是pagesJson的变更是通过endsWith,因此这里可以抓个漏洞,让uni误以为是pagesJson变更了 43 | handleHotUpdate.createHandleHotUpdate = function () { 44 | return async function (obj) { 45 | let lastLock 46 | // 使用promise锁控制前一个正在执行的server执行完再执行后续的server变更 47 | if (h5ServerUpdateLock) { 48 | lastLock = h5ServerUpdateLock 49 | await lastLock 50 | } else { 51 | h5ServerUpdateLock = createGlobalPromise() 52 | lastLock = h5ServerUpdateLock 53 | } 54 | h5Server = obj.server 55 | const newParams = {...obj} 56 | if (uniVue3HotPathList.has(obj.file) || uniVue3HotPathList.has(obj.file.replace(/\//g, '\\'))) { 57 | // newParams.file = obj.file + '.pages.json' 58 | newParams.file = 'pages.json' 59 | } 60 | const res = await oldH5HotUpdate.call(this, newParams) 61 | // 延迟一会,避免h5情况下预览出错 62 | await(new Promise((resolve) => { 63 | setTimeout(resolve, 100) 64 | })) 65 | lastLock.resolve() 66 | h5ServerUpdateLock = null 67 | return res 68 | } 69 | } 70 | } catch (e) {} 71 | 72 | const chokidar = require('chokidar') 73 | const tmp = require('tmp') 74 | const path = require('path') 75 | const callsites = require('callsites') 76 | const fs = require('fs') 77 | const Module = require('module').Module 78 | const deepFind = require('./deepFind') 79 | const oldLoad = Module._load 80 | const wrap = Module.wrap 81 | let watcher 82 | let addDependency 83 | let tmpfile = tmp.fileSync(); 84 | uniVue3HotPathList.add(tmpfile.name) 85 | 86 | function touchTmpFileChange () { 87 | let now = new Date(); 88 | fs.utimes(tmpfile.name, now, now, error => { 89 | if (error) console.error(error); 90 | }); 91 | } 92 | 93 | /** 94 | * CommonJs规范 95 | * 引入相关的js依赖,并且可以使依赖在@dcloudio/webpack-uni-pages-loader中进行热重载 96 | * 只可用于uni-app项目的pages.js中 97 | * @param mix {Object | String} loader 或者 依赖的路径 98 | * @param fromFilename {String} 调用方法的文件路径 99 | * @returns {*} mix为loader时为初始化,返回hotRequire,mix为依赖的路径时,返回依赖 100 | */ 101 | function uniPagesHotModule (mix = {}, fromFilename, pureRequire = false) { 102 | let parentPath = '' 103 | fromFilename = fromFilename || callsites()[1].getFileName() 104 | if (getPreVueContext && typeof mix === 'string') { 105 | fromFilename = mix 106 | } 107 | try{ 108 | // 尝试获取调用此方法的文件所在目录 109 | parentPath = path.dirname(fromFilename) 110 | }catch(e){} 111 | 112 | // 保留老的api 113 | function hotRequire(modulesPath){ 114 | let finalPath = path.resolve(parentPath, modulesPath) 115 | return require(finalPath) 116 | } 117 | 118 | if(mix && typeof mix === 'object' || getPreVueContext && typeof mix === 'string' && !pureRequire){ 119 | let topPath 120 | if (getPreVueContext) { 121 | topPath = path.resolve(process.env.UNI_INPUT_DIR, mix) 122 | // 模拟一个伪函数 123 | mix.__proto__.addDependency = function () {} 124 | 125 | // 校验入口js是否存在 126 | try { 127 | require.resolve(topPath) 128 | } catch (e) { 129 | console.warn(e) 130 | return 131 | } 132 | 133 | uniVue3HotPathList.add(topPath) 134 | } else { 135 | topPath = path.resolve(process.env.UNI_INPUT_DIR, 'pages.js') 136 | } 137 | 138 | if (typeof mix.addDependency === 'function') { 139 | addDependency = mix.addDependency 140 | try { 141 | // 默认将初始化的文件添加到依赖中 142 | addDependency(topPath) 143 | } catch (e) {} 144 | 145 | // 变相拦截require 146 | Module._load = function (request, parentModule, isMain) { 147 | if (!request.match(/^[.\\\/]/) && !request.match(/:/) || request.match(/\.json$/i)) { 148 | Module.wrap = wrap 149 | return oldLoad.call(this, request, parentModule, isMain) 150 | } 151 | 152 | 153 | let isHack = false 154 | 155 | let tryResolve = request 156 | // try { 157 | // tryResolve = require(request) 158 | // } catch (e) {} 159 | if (tryResolve !== topPath) { 160 | // 向上寻找父模块是否是topPath 161 | deepFind(parentModule, (child) => { 162 | if (child.parent) return [child.parent] 163 | }, (child) => { 164 | if (child.filename === require.resolve(topPath)) { 165 | isHack = true 166 | return false 167 | } 168 | }) 169 | } else { 170 | isHack = true 171 | } 172 | 173 | if (!isHack) return oldLoad.call(this, request, parentModule, isMain) 174 | 175 | const modulePath = require.resolve(request !== topPath ? path.resolve(parentModule.path, request) : request) 176 | 177 | // 注入require.context 178 | Module.wrap = function(script) { 179 | return wrap('require.context = module.constructor.hackInfo.hotRequireContext;\n' + script) 180 | } 181 | 182 | try { 183 | if (getPreVueContext) { 184 | uniVue3HotPathList.add(modulePath) 185 | } 186 | // 将模块作为依赖加到webpack的loader中 187 | addDependency(modulePath) 188 | 189 | const selfModule = require.cache[modulePath] 190 | // 先清parent中的children里的module,避免内存泄露 191 | if (selfModule && selfModule.parent && selfModule.parent.children) { 192 | selfModule.parent.children.find((m, index, arr) => { 193 | if (m === selfModule) { 194 | arr.splice(index, 1) 195 | return true 196 | } 197 | }) 198 | } 199 | // 清除模块的缓存 200 | delete require.cache[modulePath] 201 | } catch (e) {} 202 | // 这里应该重新执行一遍,因为之前清除了cache 203 | return oldLoad.call(this, request, parentModule, isMain) 204 | } 205 | } 206 | return hotRequire 207 | } 208 | 209 | if (typeof mix === 'string'){ 210 | return hotRequire(mix) 211 | } 212 | throw new Error('参数错误,只接受loader或者modulePath') 213 | } 214 | 215 | /** 216 | * 模拟webpack的require.context 217 | * 与webpack不同的地方是不会将调用此方法的模块输出,没有id属性,resolve方法返回绝对路径 218 | * @param dir 219 | * @param deep 220 | * @param fileRegExp 221 | * @returns {function(*): *} 222 | */ 223 | function hotRequireContext (dir, deep = false, fileRegExp) { 224 | const filesMap = {} 225 | let topPath = '' 226 | let ownerPath = '' 227 | try{ 228 | // 尝试获取调用此方法的文件所在目录 229 | ownerPath = callsites()[1].getFileName() 230 | topPath = ownerPath.match(/(.*)[\/\\][^\/\\]+$/)[1] 231 | }catch(e){} 232 | uniVue3HotDictList.add(topPath) 233 | let firstPath = path.resolve(topPath,dir) 234 | function findFiles (dirName) { 235 | fs.readdirSync(dirName).map((item)=>{ 236 | let absolutePath = path.resolve(dirName,item) 237 | if (deep) { 238 | // 一律都当作子目录处理 239 | try { 240 | findFiles(absolutePath) 241 | return 242 | } catch (e) {} 243 | } 244 | 245 | // 验证fileRegExp 246 | if (fileRegExp && !item.match(fileRegExp)) { 247 | return 248 | } 249 | 250 | // 去除自己避免死循环 251 | if (ownerPath === absolutePath) return 252 | 253 | const modulePath = absolutePath.replace(topPath,'.').replace(/\\\\/g,'/').replace(/\\/g,'/') 254 | if (getPreVueContext) { 255 | // uniVue3HotPathList.add(modulePath) 256 | uniPagesHotModule(absolutePath) 257 | } 258 | filesMap[modulePath] = uniPagesHotModule(absolutePath, null, true) 259 | }) 260 | } 261 | function keys () { 262 | return Object.keys(filesMap) 263 | } 264 | 265 | function resolve (relativePath) { 266 | return path.resolve(firstPath, relativePath) 267 | } 268 | 269 | function output (id) { 270 | return filesMap[id] 271 | } 272 | 273 | findFiles(firstPath) 274 | output.keys = keys 275 | output.resolve = resolve 276 | return output 277 | } 278 | 279 | uniPagesHotModule.hot = function (pagesFunction) { 280 | const fromFilename = callsites()[1].getFileName() 281 | return function (pagesJson, loader) { 282 | uniPagesHotModule(loader, fromFilename) 283 | return pagesFunction.call(this, pagesJson, loader) 284 | } 285 | } 286 | uniPagesHotModule.context = hotRequireContext 287 | // 在Module里暴露一个信息,以便require.context的注入可以获取到 288 | Module.hackInfo = { 289 | hotRequireContext 290 | } 291 | 292 | // uni vite专用,用于注册条件编译的hotJs方法 293 | uniPagesHotModule.setupHotJs = function (customName = 'hotJs') { 294 | if (getPreVueContext) { 295 | getPreVueContext[customName] = function (jsPath) { 296 | uniPagesHotModule(jsPath) 297 | return JSON.stringify(require(path.resolve(process.env.UNI_INPUT_DIR, jsPath))) 298 | } 299 | } else { 300 | throw Error('hotJs方法只支持在uni vite版本使用!') 301 | } 302 | } 303 | 304 | // uni vite专用,用于给vite.config.js添加热更新插件,此插件需配合setupHotJs使用 305 | uniPagesHotModule.createHotVitePlugin = function() { 306 | const chokidarList = new Set() 307 | return { 308 | name: 'vite:uni-hot-watch', 309 | transform () { 310 | uniVue3HotPathList.forEach(jsPath => { 311 | this.addWatchFile(jsPath) 312 | }) 313 | 314 | // rollup的缺陷(addWatchFile不能监听一个目录新增的文件触发变更) 315 | // 骚操作:创建一个临时文件让rollup监听,借助chokidar检测目录变换并且触发临时文件变更 316 | uniVue3HotDictList.forEach((dict) => { 317 | if (!chokidarList.has(dict)) { 318 | chokidarList.add(dict) 319 | watcher = chokidar.watch(dict) 320 | watcher.on("add", touchTmpFileChange); 321 | watcher.on("unlink", (modulePath) => { 322 | uniVue3HotPathList.delete(modulePath) 323 | }); 324 | } 325 | }) 326 | 327 | // Watch the tmp file instead of the src dir... 328 | this.addWatchFile(tmpfile.name); 329 | }, 330 | buildEnd() { 331 | watcher && watcher.close() 332 | } 333 | } 334 | } 335 | 336 | module.exports = uniPagesHotModule 337 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "uni-pages-hot-modules", 3 | "version": "1.0.2", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "callsites": { 8 | "version": "3.1.0", 9 | "resolved": "https://registry.npm.taobao.org/callsites/download/callsites-3.1.0.tgz", 10 | "integrity": "sha1-s2MKvYlDQy9Us/BRkjjjPNffL3M=" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "uni-pages-hot-modules", 3 | "version": "1.0.3", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "files": [ 10 | "index.js", 11 | "deepFind.js" 12 | ], 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/devilwjp/uni-pages-hot-modules.git" 16 | }, 17 | "author": "devilwjp(天堂里的花大咩)", 18 | "license": "ISC", 19 | "bugs": { 20 | "url": "https://github.com/devilwjp/uni-pages-hot-modules/issues" 21 | }, 22 | "homepage": "https://github.com/devilwjp/uni-pages-hot-modules#readme", 23 | "dependencies": { 24 | "callsites": "^3.1.0", 25 | "chokidar": "^3.5.3", 26 | "tmp": "^0.2.1" 27 | } 28 | } 29 | --------------------------------------------------------------------------------