vscode调试客户端页面的踩坑记录

2,150 阅读3分钟

前言:这两天在跟着学习如何编写简化版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服务,通过访问服务器获取页面。路漫漫其修远兮,啊菜鸟学习,靠的是真倔强,加油。


参考资料:

参考ES6模块化使用遇到的问题

Client on node: Uncaught ReferenceError: require in not defined