安装脚手架
开始一个项目,我们一般都希望使用最快最简单的方式来快速生成项目结构,然后在此基础上进行快速的开发。这个时候就要使用脚手架了,也就是根据现在的社区经验,得出来最佳初始实例。使用 react
开发的时候,我们就可以使用官方提供 create-react-app
脚手架来进行快速的开发。
这里我们使用 npm 来进行安装。
npm install -g create-react-app
# 国内用户建议使用 cnpm 进行安装
cnpm install -g create-react-app
稍等片刻我们就可以看到 create-react-app
安装结束,这个时候我们就可以使用它进行脚手架的搭建了。
初始化项目
我们可以运行create-react-app
来进行项目的初始化
# 使用这条命令来初始化一个项目, $projectName 指的是项目的名字
create-react-app $projectName
当看到这里的时候就说明项目已经初始化成功了。同时我们可以看到四条script
命令
- yarn start
- yarn build
- yarn test
- yarn eject
这四条命令是脚手架提供的,我们可以试试。当然,我们也可以使用 npm
来执行这些命令
- npm run start
- npm run build
- npm run test
- npm run eject
首先,进行到项目目录中。
cd $projectName
项目结构
.
├── README.md # 当前脚手架的说明文档,里面详细的介绍了脚手架的信息
├── node_modules # 包的安装目录
├── package.json # 项目信息
├── public # 静态资源
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json # PWA的配置文件
├── src # 代码目录,主要在里面进行开发,可以在里面自由修改目录结构
│ ├── App.css # 样式
│ ├── App.js
│ ├── App.test.js
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ └── registerServiceWorker.js # 用于在生产环境中为用户在本地创建一个service worker 来缓存资源到本地,提升应用的访问速度
└── yarn.lock
registerServiceWorker.js
首先我们查看一个这个js
文件的说明就可以看出其主要的含义了
// In production, we register a service worker to serve assets from local cache.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on the "N+1" visit to a page, since previously
// cached resources are updated in the background.
// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
// This link also includes instructions on opting out of this behavior.
其中的主要含义就是说在开发中,注册一个服务来为本地缓存提供服务。这使得应用程序在随后的访问中加载更快,并给出离线脱机的能力。但是,这也意味着开发人员将只看到部署在“N + 1”页面上的更新,因为以前缓存资源在后台更新。核心就是使用serviceWorker
来进行缓存。
这个文件主要导出了两个方法
register 方法
// 注册 service worker
export default function register() {
// 如果当前是产品环境且浏览器支持 service worker 那么就进行注册操作
// 之所以要是产品环境是因为开发环境总是进行缓存那么开发者要频繁的清空缓存才能获取最新的内容,这样不利于快速开发
// 如果浏览器不支持 service worker 那么巧妇难为无米之炊,只能放弃注册
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// 生成静态文件夹的路径,service worker 主要是用于缓存静态文件
// 关于 URL 对象可以参考 https://developer.mozilla.org/zh-CN/docs/Web/API/URL/URL
const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
// 如果静态文件与当前环境不是在同一个域下,那么注册没什么意义,那么直接返回
if (publicUrl.origin !== window.location.origin) {
return;
}
// 当页面加载完毕之后才执行 service worker 的一番操作,主要是为了避免阻塞页面的加载
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
// 如果是本地环境进行访问的,那么
if (isLocalhost) {
// 调用 checkValidServiceWorker 方法进行注册
checkValidServiceWorker(swUrl);
// 注册成功后控制台打出信息
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://goo.gl/SC7cgQ'
);
});
} else {
// 如果不是本地地址,那么只注册 service worker
// 这样做是因为此时已不再是开发环境了,开发者已经将其暴露在外网(网内网)环境中,其它用户已经可以对其进行访问了
registerValidSW(swUrl);
}
});
}
}
unregister 方法
// 取消 service worker 的注册
export function unregister() {
// 如果浏览器支持 service worker 且 service worker 处于就绪状态的时候,那么调用其提供的取消注册方法来进行操作
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}
内部方法
// 是否使用的 localhost
// 其实就是通过匹配当前地址段,然后将其强制转化成 Boolean 型常量来确定是否是本地环境
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
)
// 注册有效的 service worker
// 其中主要是通过注册 service worker 然后使用 service worker 提供的 API 来进行操作
// 比如发现有内容的更新,那么就会自动在后台进行安装,当安装结束之后再判断安装状态分别用用户进行提示
// 当然,也有异常处理,如果发生了异常,那么直接提示错误
function registerValidSW (swUrl) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
console.log('New content is available; please refresh.')
} else {
console.log('Content is cached for offline use.')
}
}
}
}
})
.catch(error => {
console.error('Error during service worker registration:', error)
})
}
// 检查 service worker 的状态
// 向 service worker 的后台服务申请资源,如果网络连接失败,或者没有获取到 javascript 那么当 service worker 状态就绪的时候取消其注册状态,并重新加载页面,如果申请到资源,那么就调用 registerValidSW 方法来进行加载。
function checkValidServiceWorker (swUrl) {
fetch(swUrl)
.then(response => {
if (
response.status === 404 ||
response.headers.get('content-type').indexOf('javascript') === -1
) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload()
})
})
} else {
registerValidSW(swUrl)
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
)
})
}
npm script
们
start
开始对项目进行开发,一般开发的时候使用。
这个时候我们打开 http://localhost:3000
或者自己内网IP下对应的 3000 端口就可以进行页面的访问了。我们可以边修改源代码边查看效果。因为这里使用了热更新技术。
build
对项目进行打包,发布到线上的时候当然不能像我们平时使用的这么随意了,这个时候我们就可打包对代码进行整合压缩。
这个时候,我们的项目就已经打包到 build 中了。把 build 中的内容拷贝到网站空间开启服务之后就可以访问了。当然,这里还给我们提供了一个简单的方案,就是把新做好的页面放到 github 所提供的静态空间中。我们可以根据它提供的方法一步一步照做即可。
test
测试 react 项目, 这个本人没有接触过,就不过多赘叙了。
eject
eject 顾名思义,弹射,这是一个不可以逆的命令。我们可以执行一下它试试。
yarn eject
这里会有一个确定项,告诉你这一项是不可逆的。这个时候可以输入 Y/N 来确定或者退出。我们按了 Y 以后,就会发现,项目中添加了很多文件。原来,以前很多细节被 create-react-app 屏蔽了,这里我们就可以看到详情并进行灵活的自己配置。