打包完的产物咋就打开白屏呢
一个相信大家在写前端初期都会遇到的问题。我们来深入研究下~
相信大部分人最近几年刚接触前后端分离,有独立JS Bundle的项目就是Vue了。这里笔者就拿一个vite+vue的项目来举例子。我们通过官方给的命令来创建个项目:
1 | pnpm create vite my-vue-app --template vue |
这个时候应该在http://localhost:5173
就可以看到vue模板的初始页面了。这个时候再执行如下命令生成构建产物:
1 | pnpm build |
执行完成之后就可以在dist
目录下看到产物文件了:
1 | dist |
这时候兴致勃勃地点开index.html
,然后就看到一个白花花的页面一脸懵逼不明白哪里不对。其实针对这个场景在vue-cli
的文档里面有写:
dist 目录需要启动一个 HTTP 服务器来访问 (除非你已经将 publicPath 配置为了一个相对的值),所以以 file:// 协议直接打开 dist/index.html 是不会工作的。在本地预览生产环境构建最简单的方式就是使用一个 Node.js 静态文件服务器
OK按这个意思我们需要本地启一个静态服务器托管它来让它工作。但是其实没有回答我们的问题,为啥一定要有个服务器?我们深入探究一下。
文档里面提到了file://
协议,这个file://
协议是让浏览器访问可以直接访问用户本地文件用的,只要给浏览器合适的路径,那么理论上浏览器就可以打开它。
我们再来看一下index.html
里面的内容:
1 |
|
可以看到里面结构很简单,核心就是通过script
标签把打包生成的js产物给引进来。只要JS产物被引进来了,那么页面就能渲染出来。既然现在页面白屏,那么肯定是这个JS没有引进来。
F12打开浏览器的控制台,可以看到这么一段报错:
Access to script at ‘file:///D:/assets/index-ATp2Kd6B.js’ from origin ‘null’ has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, isolated-app, chrome-extension, chrome-untrusted, https, edge.
报错写得很清楚了,对于我们JS文件的加载被跨域策略给拦截了。但是仔细一想不对啊,我们又没有启服务器,为什么会有跨域的问题,为啥报错里面的origin
给的是null
呢?
这个时候就要研究一下浏览器对于origin
这玩意的定义了,相关的定义在RFC-6454的3.2章节里面可以查到:
In principle, user agents could treat every URI as a separate
protection domain and require explicit consent for content retrieved
from one URI to interact with another URI. Unfortunately, this
design is cumbersome for developers because web applications often
consist of a number of resources acting in concert.
原来如此,任何输入在浏览器里面的URL都会被当做一个origin
,和是不是服务器的地址没有关系。至于origin
为啥给了个null笔者没有找到相关定义规范,但是根据Stackoverflow上的这篇回答这似乎是浏览器行为:
Origin null is the local file system, so that suggests that you’re loading the HTML page that does the load call via a file:/// URL (e.g., just double-clicking it in a local file browser or similar).
意思就是当使用file协议时origin
就会是null
。但是问题就变得更扑朔迷离了,我打开html是file协议,我加载js也是file协议,为什么会认为是跨域呢?别着急,这篇回答也解释了这个问题:
Most browsers apply the Same Origin Policy to local files by disallowing even loading files from the same directory as the document. (It used to be that Firefox allowed the same directory and subdirectories, but not any longer.
那么这个就是被浏览器的同源策略给限制了,同源策略的百科里面有这么一段话:
The behavior of same-origin checks and related mechanisms is not well-defined in a number of corner cases such as for pseudo-protocols that do not have a clearly defined host name or port associated with their URLs (file:, data:, etc.). This historically caused a fair number of security problems, such as the generally undesirable ability of any locally stored HTML file to access all other files on the disk, or communicate with any site on the Internet.
简单总结,就是为了安全性把通过file协议访问目录的行为给干掉了。
至此,所有的疑问都已经解答清楚了,一切都是为了安全性考虑。