Vue或React多页应用脚手架
yuren2013
8年前
<p>Vue或React多页应用脚手架</p> <h2>前言</h2> <p>一直以来都在研究多页应用如何能有一套像SPA一样优雅的开发模式</p> <p>本套架构在项目上使用感觉还不错(已跑在上百个页面的项目上),所以决定开源出来给大家</p> <p>阅读完本文能实现在项目中使用ES6(7)+组件化(.vue | .jsx)开发多页应用</p> <p>(其实我是想把它做为大家多页应用的脚手架)</p> <h2>目录结构介绍</h2> <p>TIPS:任何的项目的架构都和目录结构有关,所以这部分非常重要,请仔细耐心阅读</p> <p>我们先宏观的看下结构</p> <pre> |--- public // 生产环境下所需的文件 |--- static |--- css |--- es6 |--- fonts |--- images |--- views |--- src |--- assets |--- fonts |--- images |--- components |--- js |--- sass |--- static |--- css |--- es6 |--- fonts |--- images |--- views</pre> <p>src 里的 assets,components,js,sass 里的文件最后都会生成到 src/static 下,这个作为我们dev中引用的资源文件。而 public 不用说,是线上访问的文件。</p> <p>我们展开介绍下具体的页面应该如何对应它的资源。拿 js 和 views 为例</p> <pre> |--- views |--- home // 官网介绍 业务模块 |--- index.html ... |--- shopping // 购物业务模块 |--- buy.html ... |--- js |--- lib |--- vue.js |--- react.js |--- react.dom.js ... |--- home // 官网介绍业务模块的js |--- index.js ... |--- shopping // 购物业务模块的js |--- buy.js ... tools.js common.js</pre> <p>在多页应用中,往往我们的页面以业务模块划分,业务模块由许多的页面组成。</p> <p>如 home,shopping ,可能就分别为官网介绍和购物的业务模块。在这业务模块下,分别有许多个页面,那我们的js文件也需要命名一一对应。</p> <p>当然,我们还有第三方的js库是不需要编译的,所以我们专门用一个 lib 文件夹来存放他们。(包括你自己编写的指令或者filter等,不需要编译的,也直接放在lib下引入即可)</p> <p>另外,你还有许多自己写的需要编译的工具库直接放在 js 目录下即可(如,tools.js,common.js)</p> <p>我们的sass也是同理</p> <pre> |--- sass |--- home |--- index.scss ... |--- shopping |--- buy.scss ...</pre> <p>他们编译在 static 下的文件将为</p> <pre> |--- static |--- css // scss 编译后的 |--- home |--- index.css |--- shopping |--- buy.css |--- js // babel处理后的js |--- home |--- index.js |--- shopping |--- buy.js</pre> <p>页面引用的路径就为(home/index.html为例)</p> <pre> ... <link rel="stylesheet" href="../../static/css/home/index.css"> ... <script src="../../static/es6/lib/vue(react).js"></script> <script src="../../static/es6/lib/react.dom.js"></script> <script src="../../static/es6/home/index.js"></script> ...</pre> <p>js和sass搞定了后,我们的难点是编写组件的过程中,如何知道应该编译哪个入口js文件呢?</p> <p>所以我们需要对我们的组件名进行一些约定,这也就是约定大于配置的前提。</p> <pre> |--- components |--- home // home 业务模块 |--- home-header.vue(jsx) |--- index-info.vue(jsx) ... |--- shopping // shopping 业务模块 |--- buy-list.vue(jsx) ...</pre> <p>我们 components 下的业务模块名和之前的sass,js一样。具体组件那就有所不同。</p> <p>我们分为几种类型的组件</p> <ul> <li>一、当前页面使用的组件</li> <li>二、当前业务模块下的公用组件</li> <li>三、所有业务模块的通用组件</li> </ul> <p>当前页面组件的命名,我们约定为 [页面]-[组件].vue(jsx)</p> <p>如下</p> <pre> |--- components |--- home |--- index-info.vue(jsx)</pre> <p>这个 index-info 的组件就仅仅只有在 home/index.html 页面下使用,当你修改了这个组件后,会自动编译 home/index.js 路口js文件并刷新页面。</p> <p>当前业务模块下的公用组件,我们约定为 [业务模块]-[组件].vue(jsx)</p> <p>如下</p> <pre> |--- components |--- home |--- home-header.vue(jsx)</pre> <p>这个 home-header 组件就属于 home 业务模块下的公用组件,当你修改了这个组件后,会自动编译 home 业务模块下所有的js文件并刷新页面。</p> <p>剩下的就是所有业务模块下的通用组件,我们约定全放在 components/common 目录下,不需要具体命名约定</p> <pre> |--- components |--- common |--- loading.vue(jsx)</pre> <p>这个 loading 组件就属于所有业务模块下的公用组件,当你修改了这个组件后,会自动编译所有业务模块下的js文件并刷新页面。</p> <p>编译组件的原理以及为什么约定命名的原因是:</p> <p>我会根据组件更改变动,去读取文件夹名,组件名,并编译对应名的路口js</p> <p>至此,我们就把组件的问题也解决了</p> <p>由于我采用的是主gulp辅webpack,webpack仅仅只编译用,所以编译基本达到秒编译。比单纯利用webpack做构建快得多。如果单纯采用webpack做构建,需要去配置entry,配置HTMLPlugin。所以会慢得多,然而我这一套并不需要如此繁琐。</p> <h2>图片&&字体文件</h2> <p>这其实是一个大坑</p> <p>我们的实现目标是 <strong>组件能相对路径引入图片或字体文件</strong></p> <pre> // 如 在html标签里这样 <template> <figure> <img src="../../assets/images/home/logo.jpg" alt="头像"> </figure> </template> // 在style里这样 <style rel="stylesheet/scss" lang="sass"> @import "../../sass/home/index-info"; // 甚至可能在这@import面引入相对路径,这都会算是在组件里引入相对路径 #bg h3 { background: url("../../assets/images/holmes.jpg"); color: #fff; } </style></pre> <p>这个坑,真是 <strong>不可描述</strong> ,我个人尝试了各种体位,才把这个坑配置好。</p> <p>直接给大家看最后实现是怎样的。</p> <p>dev 的路径是这样,页面可以显示图片或字体。</p> <p><img src="https://simg.open-open.com/show/88bfda0efca648102ba6a3305d85b5aa.jpg"></p> <p>build 后的路径是这样</p> <p><img src="https://simg.open-open.com/show/bcb78dc60e714a5cf851a5ba30dd96c6.jpg"></p> <p>这样就达到了开发和发布后的资源统一,摸索这一步真是挺累的 T.T,有兴趣的自己看源码吧。</p> <h2>环境变量的配置</h2> <p>我们在webpack中经常会遇见不同环境下不同配置的问题</p> <p>首先可在 package.json 里配置一条 script</p> <pre> // package.json "scripts": { "build": "NODE_ENV=production gulp build", "dev": "NODE_ENV=dev gulp reload" },</pre> <p>假设我们需要为不同环境配置不同的api请求地址,就可以利用我们在 package.json 设置的 NODE_ENV 来识别当前环境(这部分我在gulpfile中处理了,所以在文件里可直接识别NODE_ENV,如下)</p> <pre> // src/js/ajaxurl.js const server1 = 'https://production.server.com'; const server2 = 'https://dev.server.com'; let useServer = null; if(NODE_ENV === 'production') { useServer = server1; } else if(NODE_ENV === 'dev') { useServer = server2; } export default useServer;</pre> <pre> // src/js/home/index.js import url from '../ajaxurl'; console.log(url);</pre> <p>这样就解决了我们不同环境下不同配置的问题,我默认配置了 dev 和 production ,大家可以自行拓展。比如</p> <p>假设你需要在 <strong>开发中</strong> 配置测试,你可以写一条 NODE_ENV=test gulp reload 。</p> <p>如果需要 <strong>预发布打包</strong> 测试,就可以另一条 NODE_ENV=preproduction gulp build 。</p> <p>总之就是打包使用 gulp build ,开发使用 gulp reload 。</p> <h2>注意事项</h2> <p>开发:执行命令 npm run dev<br> 发布:执行命令 npm run build (BTW,别忘了去 gulpfile.js 里替换你的CDN链接,进入gulp文件修改 const CDN = 'yourCDNLink'这里的变量即可)</p> <p>命名一定要按约定来!</p> <p>命名一定要按约定来!</p> <p>命名一定要按约定来!</p> <p>否则不知道要编译谁!!!</p> <p>gulp配置很简单,大家可以看一下针对各自项目进行修改,不懂得可以直接问我。</p> <p>如果你们不完全的前后端分离,把这个src直接放在后台目录下也没有问题。</p> <p>写vue和react都没问题,我把示例demo都写好了,下面是分别两个的repo地址。</p> <p>vue-multpage : <a href="/misc/goto?guid=4959713666199602772" rel="nofollow,noindex">https://github.com/MeCKodo/vue-multipage</a></p> <p>react-multpage : <a href="/misc/goto?guid=4959713666291642292" rel="nofollow,noindex">https://github.com/MeCKodo/react-multipage</a></p> <h2>TODO</h2> <ul> <li>[ ] 项目的Unit test</li> <li>[ ] 项目Cli脚手架</li> </ul> <h2>后话</h2> <p>本来是想写成 vue-cli 或者是 create-react-app 这种cli脚手架的,但是!本人真是太懒又没有时间了! 各位看官可以先尝试clone把玩把玩,如果有足够多人喜欢,我就把他写成cli,发布npm :)</p> <p>我是用mac下开发完成的,用了半天多时间专门去给window写了兼容,window还可能会有bug,不是我说! <strong>window就是辣鸡!</strong></p> <p>最后给大家看下我们的某项目结构。</p> <p style="text-align: center;">总览</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/bd296d8c3f3d0201d8bb077fbac793db.jpg"></p> <p style="text-align: center;">js部分</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/a5ef859f99f788ba6049e0374d616c4b.jpg"></p> <p style="text-align: center;">sass部分</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/f7b2f5f3ff9f2087f7f30534c400fc78.jpg"></p> <p style="text-align: center;">组件和页面</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/1d91fcb01a4201e52237e12d733fa28d.jpg"></p> <p>Have a nice day</p> <p> </p> <p>来自:http://div.io/topic/1819</p> <p> </p>