前言:这两天在跟着学习如何编写简化版React—MyReact,实践过程中难免需要调试,这时才发现自己对vscode调试客户端页面的操作几乎一无所知,于是在这里记录下学习过程,也为提醒自己今后遇到问题先理清思路再去搜索解决办法。
项目结构:
|——build
|——src
| |——App.js
| |——myreact
| |——index.js
| |——render.js
| |——createElement.js
| |——component.js
|——index.html入口文件:index.html
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title></head><body> <div id="root"></div> <script src='./App.js'></script> //App.js中使用了ES6语法如import,还使用了jsx</body></html>App.js
import MyReact from './myreact/index'const randomLikes = () => Math.ceil(Math.random() * 100);const stories = [ { name: "Didact introduction", url: "http://bit.ly/2pX7HNn", likes: randomLikes() }, { name: "Rendering DOM elements ", url: "http://bit.ly/2qCOejH", likes: randomLikes() }, { name: "Element creation and JSX", url: "http://bit.ly/2qGbw8S", likes: randomLikes() },];function storyElement(story) { return ( <li> <button onClick={e => handleClick(story)}>{story.likes}<b>❤️</b></button> <a href={story.url}>{story.name}</a> </li> );}const handleClick = (story) => { story.likes++ MyReact.render(createApp(), document.getElementById('root'))}const createApp = () => <ul> {stories.map(storyElement)} </ul> MyReact.render(createApp(), document.getElementById('root'))安装调试工具:安装debugger for chrome,并配置launch.json
{ "version": "0.2.0", "configurations": [ { "type": "chrome", "request": "launch", "name": "Launch Chrome", "url": "http://localhost:3000", "file": "${workspaceFolder}/index.html", "webRoot": "${workspaceFolder}" }, ]}知识点1:通过上述方式("type": "chrome")调试静态页面(index.html),相当于直接打开本地文件,不会启动web服务。
知识点2:JavaScript语言的发展快于浏览器,低版本的浏览器不支持ES6,所以我们通常会用babel转译ES6成为各浏览器都能识别的ES5。
试错记录:
1. 直接F5开启调试器
结果: SyntaxError: Cannot use import statement outside a module
原因:script引入含有import语句的js文件,需要添加"type = module"
2. 增加type="module"
<script type="module" src='./src/App.js'></script> //引用了含有es6语法的js文件结果:
Access to script at 'file:///E:/react-projects/myreact/src/App.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https. [file:///E:/react-projects/myreact/index.html] Failed to load resource: net::ERR_FAILED [file:///E:/react-projects/myreact/src/App.js]
原因:跨域失败。和普通script不同,ES6的module遵循同源策略(same-origin policy),而本地文件不会设置CORS头部,不能跨域,所以我们不能通过文件系统引入App.js。
经过查询资料,我得知正确的方法是创建一个本地web服务器,再通过http/https协议向服务器请求静态资源(index.html),这样才能跨域请求到App.js。
但是搭建本地服务器之前,我还想到另一个可能可行的办法并决定尝试一下。
3. babel转译ES6
既然ES6的module不能跨域,我就使用babel把ES6转译成ES5,index.html引入转译后的js文件,转译后没有了import是不是就无需跨域了呢?操作如下:
npm run babel src/ -d build
在build目录下新增的(转译后的)文件如下:

再修改index.html引入的js文件: <script src='./build/App.js'></script>
结果:
ReferenceError: require is not defined
at file:///E:/react-projects/myreact/build/App.js:3:14
原因:很好,babel把import转译成了require,require只能在node环境下使用,浏览器是识别不了的,所以此法失败。

4. 搭建本地服务器
webpack提供了webpack-dev-server来辅助开发和调试,parcel也可以为开发者启动web服务并支持调试,当然你也可以搭建自己的服务器。
总结:如果静态页面内的js脚本(或其引入的外部js文件)使用了import,即使我们使用babel转译ES6并执行(或者引用)编译后的代码,仍然不能以 访 问 本 地 文 件 的方式打开和调试静态页面,而必须以本地环境为服务器,开启web服务,通过访问服务器获取页面。路漫漫其修远兮,啊菜鸟学习,靠的是真倔强,加油。
参考资料:
Client on node: Uncaught ReferenceError: require in not defined