README
@snacking/see-u
说明
这是一个开发vue
应用的脚手架...
主要是为了解决工程拆分,以及不同项目中,将可复用的工程的重新组合成新的应用...
支持多个工程作为一个应用,同时开发、编译和部署,其中每个工程都是独立的上下文...
封装了多种插件,尽量以开关的方式简化配置...
支持webpack和vite作为开发和打包工具...
内置View UI、Element UI、Vant等UI库...
安装
在工作空间里执行以下命令,安装脚手架...
npm install @snacking/see-u
或者...
yarn add @snacking/see-u
初始化
在工作空间里执行以下命令,进行工作空间初始化...
npx sn-seeu init [-d] [-y]
在搭建脚手架时,最好是加上-d创建一个工程,如果这时不创建,也可以通过下文的一个命令创建...
npx sn-seeu init -d
-y参见[选项]说明...
[选项]
[-d --demo]
在初始化前,创建工程,并生成样例文件...[-y --yarn]
初始化后,使用yarn安装插件,否则使用npm安装插件...
执行初始化命令后,在控制台会以问答方式采集信息...
1)选择ui
库
2)如果选了ui
库,需要选择是否按需加载
3)选择css预处理语言
4)选择渲染方式(客户端渲染
、服务端渲染
)
5)选择一些插件,例如babel
、eslint
等等
6)选择是否需要后端服务
如果在初始化命令里加了-d选项,还要继续采集工程名称
...
初始化完成后,工作空间里会生成以下文件和目录...
see-u.js
工作空间的描述文件,在下文中说明package.json
node模块的描述文件如果加了-d选项,还会有个工程目录,目录里会有
index.vue
入口文件和see-u.js
工程描述文件,如果在上述问答中选了“需要后端服务”,还会有个service.js
作为后端服务样例
工作空间样例
workspace
demo
index.vue(入口文件)
router.js(路由文件)
store.js(仓库文件)
see-u.js(工程描述文件)
service.js(启用后端服务才会生成)
project1
project2
……
see-u.js(工作空间描述文件)
package.json
应用启动
在工作空间里执行以下命令...
npx sn-seeu run (webpack)
或者...
npx sn-seeu dev (vite)
默认端口为8080,可在工作空间描述文件see-u.js
中修改devServer.port
属性...
如果在上面初始化的时候,创建了一个工程,举例demo,那么可以打开工作空间描述文件see-u.js
,修改devServer.openPage
为"demo/index.html",那么应用启动后将自动打开默认浏览器访问该界面...
关于各种描述文件
see-u.js
这是脚手架的描述文件,同时存在于工作空间和工程目录里...
工程目录里的描述,主要是描述工程自身的界面入口、后端服务入口、以及该工程的依赖(同package.json里dependencies和devDependencies)...
工作空间里的描述,是开发、打包的基本设置,是脚手架运行的根本...
工作空间的see-u.js
= 脚手架预设 + 通过命令行人机交互采集的信息...
package.json
这是node模块描述文件,一般情况下仅存在于工作空间中,代表当前工作空间/应用的描述...
但也允许存在于工程目录里,作为工程的描述,主要描述工程的依赖...
由于上述工程描述已于see-u.js
中描述,所以工程目录中的模块描述大可不必,以减少描述文件数量,便于集中描述...
如果工程目录里存在模块描述,将会在编译和运行时,合并到工作空间的模块描述文件中,优先级:package.json > see-u.js...
工作空间的package.json
= 工作空间的see-u.js
+ 各工程中的package.json
+ 工作空间的package.json
,优先级从左到右依次提高...
webpack.config.js
这是webpack的描述文件,一般情况下不需要,大多数选项都可以在工作空间的see-u.js
中描述,以减少描述文件数量,便于集中描述...
但也允许存在于工作空间和工程目录里,作为各自编译描述...
在编译和运行时,将会合并工作空间和工程目录里的webpack描述,优先级:工作空间描述 > 工程描述 > see-u.js...
脚手架并不会生成工作空间的webpack.config.js,只是在编译和运行时,会依次合并相关描述,作为最终的编译参数:工作空间的see-u.js
< 各工程中的webpack.config.js
< 工作空间的webpack.config.js
...
vite.config.js
脚手架并不会生成工作空间的vite.config.js,只是运行时,根据see-u.js的配置,构建vite所需的配置对象供vite使用...
命令行
初始化
用来初始化工作空间,并安装相关依赖,可以直接创建一个工程...
npx sn-seeu init [-d] [-y]
[选项]
[-d --demo]
在初始化前,创建工程,并生成样例文件...[-y --yarn]
初始化后,使用yarn安装插件,否则使用npm安装插件...
新增工程
在工作空间里新增一个工程...
npx sn-seeu new app
webpack编译
编译工作空间,在客户端渲染时,会在工作空间的@entry目录里生成真正的入口...
npx sn-seeu build [-y]
[选项]
[-y --yarn]
用yarn安装插件...
在编译时,会校验包依赖变化,如果有变化,默认使用npm重新安装插件...
vite编译
编译工作空间,在客户端渲染时,会在工作空间的@entry目录里生成真正的入口...
npx sn-seeu compile [-y]
[选项]
[-y --yarn]
用yarn安装插件...
在编译时,会校验包依赖变化,如果有变化,默认使用npm重新安装插件...
启动应用服务
启动应用服务...
npx sn-seeu run/dev [-y]
[选项]
[-y --yarn]
用yarn安装插件...
启动前,会校验包依赖变化,如果有变化,默认使用npm重新安装插件...
应用启动后,通过{http}://{ip}:{port}/{project}/{entry}.html
访问...
其中,run是在express中注册webpack开发中间件,如果存在后端服务,同时启动后端服务...
而dev暂时是执行vite命令启动服务...
预览webpack选项
在工作空间里,生成编译和运行时webpack配置的预览webpack.preview.json
,用于校验是否符合预期...
npx sn-seeu preview
see-u.js的描述说明
{
mode: "production", // webpack/vite的内置优化模式,production | development | none
devServer: {
port: 8080, // 端口
hot: true, // 模块热替换
openPage: "demo/index.html" // 应用启动后打开的默认页
},
development: {
"vue": {
"runtime": true, // 引用运行时模块(将不能动态解析模板)
"route": {
"paramsToProps": true // 将路由参数送入组件的props属性
},
"config": {
"devtools": false, // 开发工具
"productionTip": false // 生产模式的消息
},
"plugins": [] // vue插件列表,具体参见下文专项说明
},
"ui": {
"lib": "Vant", // ui库,目前Vue支持View UI、Element UI、Vant
"asNeeded": false // ui按需加载
},
"css": {
"inline": false, // 内联css
"minified": true // 压缩
"preprocessor": "Less", // css预处理语言,目前支持Less、Sass,如果不使用设置None
"variable": null // 自定义变量文件,在使用css预处理器时导入
},
"ajax": {
"formData": false, // post/put等请求body中的数据格式,false默认使用application/json,true默认使用application/x-www-form-urlencode
"security": {
"crypto": false, // 解密功能开关
"placeholder": "SayHi" // 框架用来识别加密请求的占位符
}
},
"log": {
"domEvent": false, // dom事件日志开关
"domEventTypes": ["click"], // 需要监听的dom事件
"method": false, // 组件方法调用日志开关
"ajax": false, // ajax请求日志开关
"serverPath": null // 日志发送服务地址,如果没设置,则默认在控制台输出
},
"csr": true, // 客户端渲染开关
"ssr": false, // 服务端渲染开关
"eslint": false, // eslint开关
"babel": false, // babel开关
"polyfill": false, // 垫片开关,要先开启babel开关
"clear": true, // 编译前清空编译目录
"mock": false, // mock开关
"proxy": false, // proxy开关
"service": false // 后端服务开关
},
chunk: { // 需要剥离的模块
vue: "vue"
},
entry: null, // webpack的入口,非必须
context: null, // 基础目录,非必须,默认为cwd
output: null, // 非必须
plugins: null, // 插件,非必须
externals: null, // 外部扩展,非必须
module: null, // 非必须
optimization: null, // 优化选项,非必须
performance: null, // 性能,非必须
resolve: null // 非必须
----------------------------- 以上仅在工作空间里描述使用
----------------------------- 以下仅在工程里描述使用
dependencies: {}, // 依赖,非必须
devDependencies: {}, // 开发依赖,非必须
entryForVue: { // vue单文件入口,需开启客户端渲染
index: {
"path": "./index.vue", // vue单文件入口
"title": "hello! see u!", // 页面title
"router": null, // 路由
"store": null, // 仓库
"favicon": null, // 图标
"meta": null
}
},
service: { // 后端服务入口,需开启后端服务
"/test": "./service/test.js"
},
ssrForVue: { // 服务端渲染入口,需开启服务端渲染
"/": {
"path": "./index.vue",
"router": "./router.js",
"store": "./store.js"
}
}
}
development.vue.plugins说明
这里用来指定使用哪些vue插件...
插件约定:
export default function (option) {
return function (Vue) {
// Vue插件内容
}
};
配置约定:
plugins: [
"@snacking/see-u/bin/vue/plugins/prototype/event", // 字符串形式,插件位置
{ // 对象形式
Ajax: "@snacking/see-u/bin/vue/plugins/prototype/ajax", // 插件名称以及位置
option: "ajax" // 选项,送入插件的参数,即插件约定中的option
}
]
在对象形式中,选项的键必须是option,值可以是字符串、对象,或者是包含这两者的数组...
如果值是字符串,则表示取自development
下的指定属性,比如development.ajax
...
如果值是对象,可以是对象字面量,或者某个对象的引用...
如果值是包含字符串或者对象的数组,则按上述规则按顺序合并成一个对象...
客户端渲染
在工程的see-u.js
里的entryForVue
属性,以键值对的方式,映射入口名称与实际模块的关系...
"entryForVue": {
"index": {
"path": "./index.vue",
"title": "hello! see u!"
"router": "./router.js",
"store": "./store.js",
"favicon": null,
"meta": null
}
}
理论上支持 html-webpack-plugin
的所有选项(不过有些选项还没处理-。-!)...
服务端渲染
在工程的see-u.js
里的ssrForVue
属性,以键值对的方式,映射路由名与实际模块的关系...
"ssrForVue": {
"/": {
"path": "./index.vue",
"router": "./router.js",
"store": "./store.js"
}
}
在需要多页面时,只要设置上下文,区分路由名...
"ssrForVue": {
"/index1": {
"path": "./index1.vue",
"router": "./router1.js",
"store": "./store1.js"
},
"/index2": {
"path": "./index2.vue",
"router": "./router2.js",
"store": "./store2.js"
}
}
后端服务
在工程的see-u.js
里的service
属性,以键值对的方式,映射服务名与实际模块的关系...
"service": {
"/test": "./service/test.js"
}
在同一个工程中可以通过fetch("./test")
请求...
如果是其他工程,可以通过fetch("/工程名/test")
请求...
在服务名前面可以加入Method指定方法名,则只能使用相应方法才能访问,如果不设置则不限制
"service": {
"GET ./test": "./services/test.js"
}
在实际模块前面可以加入Router标识,表明该模块将返回一个express的Router对象,而不是单一服务
"service": {
"./test": "Router ./services/test.js"
}
注意:Method名称和Router标识不能同时使用,因为在Router里已经由模块控制了Method名称,以下是错误例子,可能返回404
"service": {
"POST ./test": "Router ./services/test.js"
}
mock说明
在工程目录下创建mock.js...
module.exports = {
'GET /api/user': { id: 1, username: 'test' },
'POST /api/user/list': [
{ id: 2, username: 'temp' }
]
};
配置可参考mocker-api
proxy说明
在工程目录下创建proxy.js...
module.exports = {
'/widgets/*': {
target: 'http://127.0.0.1/demo/',
secure: false,
changeOrigin: true
}
}
或者在工程或者工作空间里的see-u.js
或者webpack.config.js
的devServer
节点里加入配置...
proxy: {
'/widgets/*': {
target: 'http://127.0.0.1/demo/',
secure: false,
changeOrigin: true
}
}
服务地址切换
以上的mock和proxy,都是在本地服务器创建代理...
提供一种服务地址切换方案...
services.js
这是独立的服务地址文件,文件名任意,允许多个文件,内容以////// autoService
开头,服务地址需要以对象字面量作为默认导出...
////// autoService
const base = "http://10.6.8.1:8060"
export default {
"service1": `/widgets/widget | ${base}/widgets/widget`
};
每个服务地址是一个字符串或者字符串模板,测试地址和生产地址之间使用|
(3个字符,为空格 + | + 空格)隔开,前面的是测试地址,后面的生产地址...
test.js
请求服务时,导入上述对象,用对象的属性代替字符串字面量或者变量作为入参...
import services from "./services";
fetch(services.service1)
当工作空间的see-u.js
描述中的mode
属性为production
时,将会使用生产地址,其他值会使用测试地址...
如果地址中没有|
,即不区分测试和生产时,mode
无论是什么值都会直接使用这个地址...
该方案只是做服务地址切换,而不做跨域处理。实际生产地址可以是nginx代理地址,或者服务端增加access-control-allow-origin属性等跨域手段...
对Vue的扩展
http请求
在Vue的原型里扩展了$http属性,在组件中通过this.$http可获取到ajax实例,该实例提供以下方法...
request - 通用的请求
this.$http.request(url, options)
this.$http.request(options)
delete - 请求delete服务
this.$http.delete(url, options)
get - 请求get服务
this.$http.get(url, options)
head - 请求head服务
this.$http.head(url, options)
options - 请求options服务
this.$http.options(url, options)
post - 请求post服务
this.$http.post(url, data, options)
put - 请求put服务
this.$http.put(url, data, options)
patch - 请求patch服务
this.$http.patch(url, data, options)
all - 并发请求
this.$http.all(requests)
create - 创建新的ajax实例
this.$http.create(options)
getCancelToken - 获取取消令牌
this.$http.getCancelToken()
以上可以参考axios说明文档...
自定义ajax
在组件中通过this.$http.create(options)
方法创建新的ajax实例,具体选项可以参考axios说明文档...
全局事件
在Vue的原型里扩展了$event属性,在组件中通过this.$event可获取到事件实例...
this.$event.$on()
this.$event.$emit()
跨文档消息
在Vue的原型里扩展了$xdm属性,允许在组件里以事件的方式进行跨文档消息传输...
on - 绑定事件
this.$xmd.on(identifier, callback)
identifier
事件标识callback
回调函数
off - 解绑事件
this.$xmd.off(identifier, callback)
identifier
事件标识callback
回调函数
emit - 触发事件
this.$xmd.emit(target, identifier, data)
target
消息发往的目标,可以是iframe,可以是open的窗口,或者其他window窗口identifier
事件标识data
发送的数据
事件防抖指令
v-debounce
在该指令的修饰符中,指定相关事件的防抖参数,一个完整的修饰符如event,wait,maxWait,leading,trailing,支持多个修饰符...
修饰符说明
event: 事件名称,例如click、change等,必须
wait: 延迟的毫秒数,非必须,默认为0
maxWait: 允许被延迟的最大值,无默认
leading: 指定在延迟开始前调用,默认false
trailing: 指定在延迟结束后调用,默认true
例子
<Button v-debounce.click,500 @click="btnClick">防抖指令测试</Button>
多个修饰符
<Button v-debounce.click,500.change,200 @click="btnClick">防抖指令测试</Button>
事件节流指令
v-throttle
在该指令的修饰符中,指定相关事件的防抖参数,一个完整的修饰符如event,wait,leading,trailing,支持多个修饰符...
修饰符说明
event: 事件名称,例如click、change等,必须
wait: 延迟的毫秒数,非必须,默认为0
leading: 指定在延迟开始前调用,默认false
trailing: 指定在延迟结束后调用,默认true
例子
<Button v-throttle.click,500 @click="btnClick">节流指令测试</Button>
多个修饰符
<Button v-throttle.click,500.change,200 @click="btnClick">节流指令测试</Button>
权限校验指令
v-auth
支持disable修饰符,如果指定disable,则在无权限的时候,将元素设置为disabled,否则删除当前元素...
支持role修饰符,如果指定,则把指令值(value)作为角色标识,否则将指令值作为权限标识...
指令值(value)为字符串,多个则以逗号分隔...
<Button v-auth="submit">指令测试</Button>
<Button v-auth.disable="submit">指令测试</Button>
<Button v-auth.disable.role="monitor">指令测试</Button>
使用该指令前,需要在see-u.js
中的development.vue.plugins
插件配置中,给@snacking/see-u/bin/vue/plugins/directives/auth
插件传递一个用来校验权限的方法
const auth = require("./auth");
……
{
"Auth": "@snacking/see-u/bin/vue/plugins/directives/auth",
"option": {
"handler": auth
}
}
该方法约定为function(type, values)
,其中type
为类型,值为role或者auth;values
是权限或者角色,是一个字符串数组...
关于vue-router
路由文件配置在see-u.js
描述中的entryForVue
或者ssrForVue
入口的router
属性中...
路由文件允许导出以下对象
- VueRouter实例,即new VueRouter(options)
- VueRouter的选项,即options(推荐)
- VueRouter选项中的routes属性,即options里的routes属性
推荐导出VueRouter的选项(options)
- 由脚手架根据选项生成唯一路由实例
- 在
see-u.js
描述中,通过route.paramsToProps开关,自动设置路由配置中的props属性,将params通过组件的props属性传递 - 全局守卫可在options中描述,脚手架会将其注册在生成的路由实例中
关于Vue组件大量导入和局部注册的解决方案
当ui库按需加载,或者大量导入组件,或者需要按目录导入组件时,导入和局部注册都是繁琐的...
提供一种编写注释块来实现自动导入和局部注册的方案:
/**
* @loader autoImport
* @ui Button,Col,Row,Checkbox
* @comps ./user,./order.vue
* @path ./page,../image
* @recursivePath ./components,../flows
*/
@loader autoImport
注释快描述@ui
ui组件名,根据当前项目配置的ui库进行导入和注册,多个用逗号分隔@comps
明确的组件名,多个用逗号分隔@path
指定目录下的所有组件,多个用逗号分隔@recursivePath
指定目录下的所有组件,含所有子目录里的组件,多个用逗号分隔
注意:使用逗号分隔时,中间不能有空格...