填坑:在 SegmentFault 开发单页应用之图片引用的问题探索
前言
前段时间,SegmentFault 低调上线了 技术号 模块,方便用户对数据进行集中管理。在开发过程中,第一次引入了 MV* 框架。
SF 的基本架构还是后端路由,这也使得页面频繁地整体请求,体验非常不好。而技术号这个模块,不依赖 SEO,侧边导航又具有非常强烈的可切换性,所以适当地引入一个 MV* 框架是非常合适的。基于此考虑,决定在这个模块的开发中引入 Vue.js。
SF 目前的前端架构是非常传统的,jQuery+BootStrap+Requirejs+Gulp 的开发组合,r.js 做上线前的打包。如何将 Vue.js 应用进入目前的架构?其实非常简单,遵循一个原则即可,r.js 最后打包成一个 js 文件,而 webpack 最后也是打包成一个 js 文件。
我们用 webpack-dev-server 起前端 server 后,在内存中生成的 js 的路径类似 localhost:8080/xxx.js,然后在后端模版中引用这个 js 即可。值得注意的是,必须写死绝对路径,所以只能指定端口,目前我还没有找到更好的办法解决这个问题。
图片引用
其他部分的开发,比如 js 和 css 都没有什么大的问题,图片的引用成了问题。在第一次上线时我用了线上的绝对路径,这显然是不合理的。
之前的图片引用,其实是依赖后端的。前端上线时,会有一个文件夹包含所有的 js、css 以及图片文件,然后将这个文件夹重命名(重命名成一个哈希版本号),再上传到 CDN。所以如果独立打开 js、css 或者图片文件,其实路径上是会有一个版本号的。
那么目前线上是如何解决的?目前应用图片的地方主要是后端模版文件以及 css。如果是后端模版文件,引用图片时会先调用一个后端函数,这个函数会返回图片路径,很显然开发环境和线上环境这个路径的结果是不同的。同样,js 和 css 的引入,都会被这个函数先调用才返回引用路径。而在 css 中引用图片就没啥问题了,只是个相对路径的事。
而将图片引用放入前端了呢?图片的路径和 js 的路径具有某种联系,本质是需要获取这个哈希版本号。问题在于,如何获取正在执行的 js 文件的路径?其实这很像是一道脑筋急转弯,如果习惯了 Node 的方式,可能会从 __dirname
和 process.cwd()
去入手,但是很遗憾虽然客户端也能引入 process 、path 等包,但是获取不到类似的值。答案也很简单,直接获取 script 的 dom 节点,然后取 src 即可,就是完美的绝对路径。另外还有个方法,可以用 document.currentScript.getAttribute('src')
,但是 src 赋值的字符串是什么,它就是什么,而且在实际开发中莫名报错,所以我用了前者。
cdn: src => {
let jsPath = document.getElementById('indexScript').src.replace(/script.*/, 'img/')
src = jsPath + src
return src
}
这样就粗暴地解决了线上图片引用的问题。
开发 VS 线上
但是本地开发引用图片的问题还没有解决。
综上所述,本地开发起的前端 server,其实是用了绝对地址 localhost:8080/xxx.js,如果用以上规则获取图片,很显然获取的还是 localhost:8080 域名下的图片,我们需要将其切换到后端路由的测试域名下。
也就是规则类似 localhost:8080/build/xxx/img/xxx.png 的请求都需要转到另外一个域名下(实际开发中是 sf.testapp.org),chrome 下有个神器 ReRes 可以轻易做到。
配置如下:
// If URL match
http://localhost:8080/build/(.*)/img/
// Response
http://sf.testapp.org/build/$1/img/
这样就粗暴解决了开发环境引用不到图片的问题。
待续
这并不是终点。其实目前的图片是放在最终上线的静态文件文件夹中,和 Vue.js 整个开发项目剥离,这并不是一个好的方式。最好的方式肯定是放在 Vue.js 项目中,比如 assets 或者 static 文件夹下。这就需要在前端引用图片的时候判断是开发还是线上环境,分别引用不同地址,开发完后,打包前需要将项目中的图片同步到需要上线的静态文件文件夹中。还有另一种方案,开发和线上引用一个地址,但是开发环境引用时再做一次映射,跳到 Vue.js 项目内。
目前还没考虑这点,因为这只是 MV* 的第一次尝试,文件目录的结构还没最终确定。
思考
这个功能的开发其实不具有典型的参考意义,我称之为 "走 SF 特色的一次开发尝试"。毕竟需要前后端路由混杂,而且还和最终线上打包方式有关,只能因地制宜,走自己的路。
这让我想到了之前一位前辈对我说的话:
前端的主要竞争力还是学习能力,程序员的竞争力是解决问题的能力。
共勉之
填坑:在 SegmentFault 开发单页应用之图片引用的问题探索的更多相关文章
- Laravel 5.5 + Vue 开发单页应用
上次我用 laravel5.3 + Vue 开发了一个简单的单页应用,这次我打算将其升级到 laravel5.5,在升级的过程中,做一下记录,其源码放在 github 上面,源码地址 开发环境 软 ...
- 使用Vue快速开发单页应用
本文所涉及代码全在vue-cnode 单页应用,即在一个页面集成系统中所有功能,整个应用只有一个页面.因为路由的控制在前端,单页面应用在页面切换时比传统页面更快,从而在前端体验更好. 将逻辑从后端转移 ...
- 【前端vue开发架构】vue开发单页项目架构总结
为营销活动设计的前端架构 主要的技术栈为 Vuejs,Webpack,请自行阅读如下技术或者框架的文档: 一.基础说明: node (https://nodejs.org/en/) npm (http ...
- 基于环信SDK的IM即时通讯填坑之路(vue)
公司最近使用第三方环信SDK的进行通信聊天,基本已完成.记录下填坑之路 1.可以通过以下方式引用 WebSDK 1.安装 npm install easemob-websdk --save 2. 先 ...
- Android Tips – 填坑手册
出于: androidChina http://www.androidchina.net/3595.html 学习 Android 至今,大大小小的坑没少踩,庆幸的是,在强大的搜索引擎与无私奉献的 ...
- webapp填坑记录[更新中]
网上也有许多的 webapp 填坑记录了,这几个月,我在公司正好也做了2个,碰到了一些问题,所以我在这里记录一下我所碰到的问题: meta 头部声明在开发的时候,刚刚创建 HTML 文件,再使用浏览器 ...
- webapp填坑记录
网上也有许多的 webapp 填坑记录了,这几个月,我在公司正好也做了2个,碰到了一些问题,所以我在这里记录一下我所碰到的问题: meta 头部声明在开发的时候,刚刚创建 HTML 文件,再使用浏览器 ...
- 微信公众号支付备忘及填坑之路-java
一.背景 最近公司给第三方开发了一个公众号,其中最重要的功能是支付,由于是第一次开发,遇到的坑特别的多,截止我写博客时,支付已经完成,在这里我把遇到的坑记录一下(不涉及退款).不得不吐槽一下,腾讯这么 ...
- css 填坑常用代码分享
以下是常用的代码收集,没有任何技术含量,只是填坑的积累.转载请注明出处,谢谢. 因为提交比较麻烦,后来转置github:https://github.com/jsfront/src/blob/mast ...
随机推荐
- TCP/IP(六)应用层(DNS和HTTP协议)
前言 到这一篇我已经把TCP/IP五层模型详细的说明了一遍,大体的从物理层到最上层的应用层做了一个大概的了解,其实总体学下来东西非常的多,我们需要经常的去系统性的去学习它.不然过一段时间就忘记了! 回 ...
- BZOJ 1046: [HAOI2007]上升序列【贪心+二分状态+dp+递归】
1046: [HAOI2007]上升序列 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4987 Solved: 1732[Submit][Stat ...
- 2017ecjtu-summer training #11 POJ 1018
Communication System Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 29218 Accepted: ...
- input[type=file]样式更改以及图片上传预览
以前知道input[type=file]可以上传文件,但是没用过,今天初次用,总感觉默认样式怪怪的,想修改一下,于是折腾了半天,总算是小有收获. 以上是默认样式,这里我想小小的修改下: HTML代码如 ...
- 什么是命名空间?php命名空间的基本应用分享
什么是命名空间? php中声明的函数名.类名和常量的名称,在同一次运行中是不能重复的,否则会产生一个致命的错误,常见的解决方法是约定一个前缀.例如 ,在项目开发时,用户 User 模块中的控制器和数据 ...
- UE4 AsnycTask
使用AsnycTask可以将制定代码放在指定线程中执行,例如更新文理必须放在游戏线程. AsyncTask(ENamedThreads::GameThread, [=](){ updateT ...
- javascript数据类型及转换
此篇数据类型和转换只限于ECMA规范,规范用了比较大的篇幅讲数据类型和类型转换,理解了这个最基本的概念对表达式.语句.执行环境.对象及继承都有非常大的帮助,遂整理如下: 数据类型和值 类型转换 表达式 ...
- Spark算子--union、intersection、subtract
转载请标明出处http://www.cnblogs.com/haozhengfei/p/252bcc1d1ab30c430d347279d5827615.html union.intersection ...
- 查询A、B表中,A表中B表没有的数据
A.B两表,找出ID字段中,存在A表,但是不存在B表的数据.A表总共13w数据,去重后大约3W条数据,B表有2W条数据,且B表的ID字段有索引. 方法一 使用 not in ,容易理解,效率低 ~执 ...
- [机器学习]模型评价参数,准确率,召回率,F1-score
很久很久以前,我还是有个建筑梦的大二少年,有一天,讲图的老师看了眼我的设计图,说:"我觉得你这个设计做得很紧张".当时我就崩溃,对紧张不紧张这样的评价标准理解无能.多年后我终于明白 ...