一、开发环境
1、开发环境
- windows 10操作系统;
- Node.js v10.16.0;
- webstorm 2019.3.4 x64;
2、前端技术栈
- react v16.13.1 hooks + redux v7.2 + react-router v5.1.2;
- antd v4.1.0;
- marked hightlight.js;
- webpach打包优化;
- axios封装;
3、后端技术栈
- spring boot;
- mybatis-plus;
- swagger;
- spring security;
二、前端知识回顾
1、基础学习
如果没有接触过react的话,推荐先学习一下react基础知识:
1、react的入门教学视频入口:React 入门教程(开发文档);
2、官方教程入口:入门教程: 认识 React;
3、redux教程:从零实现一个 redux;
2、命名规范
html标签:小写字符开始;
自定义React组件:大写字符开始;
其它变量、方法、函数:驼峰命名法;
文件夹、文件命名:全部小写,中间使用_分割,如data_assets;
三、npm使用
1、npm介绍
npm是随同Node.js一起安装的包管理工具,能解决Node.js代码部署上的很多问题,常见的使用场景有以下几种:
- 允许用户从npm服务器下载别人编写的第三方包到本地使用;
- 允许用户从npm服务器下载并安装别人编写的命令行程序到本地使用;
- 允许用户将自己编写的包或命令行程序上传到npm服务器供别人使用;
由于新版的Node.js已经集成了npm,所以npm也一并安装好了。同样可以通过输入如下命令 来测试是否成功安装。命令如下,出现版本提示表示安装成功:
npm -v
2、npm使用
如果你安装的是旧版本的 npm,可以很容易得通过 npm 命令来升级,命令如下:
npm install npm -g
由于npm安装较慢,我们可以使用淘宝镜像的命令:
npm install -g cnpm --registry=https://registry.npm.taobao.org
这样就可以使用 cnpm 命令来安装模块了:
npm 安装 Node.js 模块语法格式如下:
npm install
以下实例,我们使用 npm 命令安装常用的 Node.js web框架模块 express:
npm install express
安装好之后,express 包就放在了工程目录下的 node_modules 目录中,因此在代码中只需要通过 require('express') 的方式就好,无需指定第三方包路径。
var express = require('express');
3、全局安装与本地安装
npm 的包安装分为本地安装(local)、全局安装(global)两种,从敲的命令行来看,差别只是有没有-g而已,比如:
npm install express # 本地安装
npm install express -g # 全局安装
本地安装
- 将安装包放在 ./node_modules 下(运行 npm 命令时所在的目录),如果没有 node_modules 目录,会在当前执行 npm 命令的目录下生成 node_modules 目录;
- 可以通过 require() 来引入本地安装的包;
全局安装
- npm 全局模块的存放路径以及cache的路径的配置,默认是在 C 盘 "C:\Users\用户" 下;
- 可以直接在命令行里使用;
我们可以指定全局模块以及cache路径:
(1).在 nodejs 安装目录下,创建 ”node_global” 和 ”node_cache” 两个文件夹;
(2). 进入 cmd 命令行,输入如下命令:
npm config set prefix "D:\nodejs\node_global"
npm config set cache "D:\nodejs\node_cache"
设置全局模块的安装路径到 "node_global" 文件夹, 设置缓存到 "node_cache" 文件夹;
(3).由于 node 全局模块大多数都是可以通过命令行访问的,还要把 “D:\nodejs\node_global” 加入到系统环境变量 PATH 中,方便直接使用命令行运行;
查看安装信息
你可以使用以下命令来查看所有全局安装的模块:
npm list -g
4、使用 package.json
package.json 位于模块的目录下,用于定义包的属性。接下来让我们来看下 express 包的 package.json 文件,位于 node_modules/express/package.json 内容:

{
"name": "express",
"description": "Fast, unopinionated, minimalist web framework",
"version": "4.13.3",
"author": {
"name": "TJ Holowaychuk",
"email": "[email protected]"
},
"contributors": [
{
"name": "Aaron Heckmann",
"email": "[email protected]"
},
{
"name": "Ciaran Jessup",
"email": "[email protected]"
},
{
"name": "Douglas Christopher Wilson",
"email": "[email protected]"
},
{
"name": "Guillermo Rauch",
"email": "[email protected]"
},
{
"name": "Jonathan Ong",
"email": "[email protected]"
},
{
"name": "Roman Shtylman",
"email": "[email protected]"
},
{
"name": "Young Jae Sim",
"email": "[email protected]"
}
],
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/strongloop/express.git"
},
"homepage": "http://expressjs.com/",
"keywords": [
"express",
"framework",
"sinatra",
"web",
"rest",
"restful",
"router",
"app",
"api"
],
"dependencies": {
"accepts": "~1.2.12",
"array-flatten": "1.1.1",
"content-disposition": "0.5.0",
"content-type": "~1.0.1",
"cookie": "0.1.3",
"cookie-signature": "1.0.6",
"debug": "~2.2.0",
"depd": "~1.0.1",
"escape-html": "1.0.2",
"etag": "~1.7.0",
"finalhandler": "0.4.0",
"fresh": "0.3.0",
"merge-descriptors": "1.0.0",
"methods": "~1.1.1",
"on-finished": "~2.3.0",
"parseurl": "~1.3.0",
"path-to-regexp": "0.1.7",
"proxy-addr": "~1.0.8",
"qs": "4.0.0",
"range-parser": "~1.0.2",
"send": "0.13.0",
"serve-static": "~1.10.0",
"type-is": "~1.6.6",
"utils-merge": "1.0.0",
"vary": "~1.0.1"
},
"devDependencies": {
"after": "0.8.1",
"ejs": "2.3.3",
"istanbul": "0.3.17",
"marked": "0.3.5",
"mocha": "2.2.5",
"should": "7.0.2",
"supertest": "1.0.1",
"body-parser": "~1.13.3",
"connect-redis": "~2.4.1",
"cookie-parser": "~1.3.5",
"cookie-session": "~1.2.0",
"express-session": "~1.11.3",
"jade": "~1.11.0",
"method-override": "~2.3.5",
"morgan": "~1.6.1",
"multiparty": "~4.1.2",
"vhost": "~3.0.1"
},
"engines": {
"node": ">= 0.10.0"
},
"files": [
"LICENSE",
"History.md",
"Readme.md",
"index.js",
"lib/"
],
"scripts": {
"test": "mocha --require test/support/env --reporter spec --bail --check-leaks test/ test/acceptance/",
"test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/ test/acceptance/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
"test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/"
},
"gitHead": "ef7ad681b245fba023843ce94f6bcb8e275bbb8e",
"bugs": {
"url": "https://github.com/strongloop/express/issues"
},
"_id": "[email protected]",
"_shasum": "ddb2f1fb4502bf33598d2b032b037960ca6c80a3",
"_from": "express@*",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "[email protected]"
},
"maintainers": [
{
"name": "tjholowaychuk",
"email": "[email protected]"
},
{
"name": "jongleberry",
"email": "[email protected]"
},
{
"name": "dougwilson",
"email": "[email protected]"
},
{
"name": "rfeng",
"email": "[email protected]"
},
{
"name": "aredridel",
"email": "[email protected]"
},
{
"name": "strongloop",
"email": "[email protected]"
},
{
"name": "defunctzombie",
"email": "[email protected]"
}
],
"dist": {
"shasum": "ddb2f1fb4502bf33598d2b032b037960ca6c80a3",
"tarball": "http://registry.npmjs.org/express/-/express-4.13.3.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/express/-/express-4.13.3.tgz",
"readme": "ERROR: No README data found!"
}
Package.json 属性说明
-
name - 包名;
-
version - 包的版本号;
-
description - 包的描述;
-
homepage - 包的官网 url ;
-
author - 包的作者姓名;
-
contributors - 包的其他贡献者姓名;
-
dependencies - 依赖包列表。如果依赖包没有安装,npm 会自动将依赖包安装在 node_module 目录下;
-
repository - 包代码存放的地方的类型,可以是 git 或 svn,git 可在 Github 上;
-
main - main 字段指定了程序的主入口文件,require('moduleName') 就会加载这个文件。这个字段的默认值是模块根目录下面的 index.js;
-
keywords - 关键字;
5、卸载模块
我们可以使用以下命令来卸载 Node.js 模块:
npm uninstall express
6、更新模块
我们可以使用以下命令更新模块:
npm update express
7、搜索模块
使用以下来搜索模块,会打开浏览器查看存在的模块版本:
npm search express
四、快速构建React开发环境
1、全局安装create-react-app脚手架工具
cnpm install -g create-react-app
create-react-app 是来自于 Facebook,通过该命令我们无需配置就能快速构建 React 开发环境。 create-react-app 自动创建的项目是基于 Webpack + ES6 。
2、创建新的react项目
create-react-app react-blog-zy
此时会在当前工作路径创建一个文件夹react-blog-zy:
- node_modules:用于存放项目的依赖包,也就是构建这个React项目可能会用到的工具;
- public:文件夹是 index.html文件的存放目录;
- src:用于存放js文件,也就是项目开发中的主要区域;
- package.json:用于记录项目信息,以及外部依赖包的导入信息等;
跳转到新建项目目录下:
cd react-blog-zy
运行项目:
npm start
可以看到项目启动成功,打开网页 http://localhost:3000:
3、运行npm run eject
使用npm run eject 可以看到webpack.config配置信息,此时会多出两个文件夹:
config文件夹:
- env.js :处理.env环境变量配置文件;
- path.js:提供各种路径;
- webpack.config.js: webpack配置文件;
- webpackDevServer.config.js:测试服务器配置文件;
env.js用来处理.env文件中配置的环境变量:
const NODE_ENV = process.env.NODE_ENV;
if (!NODE_ENV) {
throw new Error(
'The NODE_ENV environment variable is required but was not specified.'
);
}
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
const dotenvFiles = [
`${paths.dotenv}.${NODE_ENV}.local`,
`${paths.dotenv}.${NODE_ENV}`,
// Don't include `.env.local` for `test` environment
// since normally you expect tests to produce the same
// results for everyone
NODE_ENV !== 'test' && `${paths.dotenv}.local`,
paths.dotenv,
].filter(Boolean);
// Load environment variables from .env* files. Suppress warnings using silent
// if this file is missing. dotenv will never modify any environment variables
// that have already been set. Variable expansion is supported in .env files.
// https://github.com/motdotla/dotenv
// https://github.com/motdotla/dotenv-expand
dotenvFiles.forEach(dotenvFile => {
if (fs.existsSync(dotenvFile)) {
require('dotenv-expand')(
require('dotenv').config({
path: dotenvFile,
})
);
}
});
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'development';
process.env.NODE_ENV = 'development';
dotenvFiles 是一个数组,保存要扫描的.env*文件,然后遍历每个文件,从这些文件中加载环境变量;
scripts文件夹:
- build.js:打包脚本;
- start.js: 启动脚本;
- test.js: 测试脚本;
我们可以通过修改脚本,指定项目运行在其它端口:
// Tools like Cloud9 rely on this.
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
const HOST = process.env.HOST || '0.0.0.0';
4、项目结构调整
删除src、public目录下所有文件:
1、在public下新建index.html文件:
"en"> <head> "utf-8" /> "icon" href="%PUBLIC_URL%/favicon.ico" /> "viewport" content="width=device-width, initial-scale=1" /> "theme-color" content="#000000" /> <meta name="description" content="Web site created using create-react-app" /> "manifest" href="%PUBLIC_URL%/manifest.json" />zy的博客 "keywords" content="zy的博客"> "keywords" content="zy"> "description" content="前端开发爱好者"> "og:type" content="website"> "og:title" content="zy的博客"> "og:url" content="https://www.cnblogs.com/zyly/"> "og:site_name" content="zy的博客"> "og:description" content="前端开发爱好者"> "twitter:card" content="summary"> "twitter:title" content="zy的博客"> "twitter:description" content="前端开发爱好者"> "viewport" content="width=device-width,initial-scale=1,user-scalable=no"> head>id="root">
2、在public下新建favicon.ico文件:
该文件就是一个icn图标;
3、在public下新建manifest.json文件:
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
4、在src下新建App.js文件:
import React from 'react';
export default function App(props){
return (
博客
)
}
5、在src下新建index.js文件:
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
ReactDOM.render(
,
document.getElementById('root')
)
该文件也是该项目的默认入口文件,我们可以在webpack.config.js文件中看到:
// These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle.
entry: [
// Include an alternative client for WebpackDevServer. A client's job is to
// connect to WebpackDevServer by a socket and get notified about changes.
// When you save a file, the client will either apply hot updates (in case
// of CSS changes), or refresh the page (in case of JS changes). When you
// make a syntax error, this client will display a syntax error overlay.
// Note: instead of the default WebpackDevServer client, we use a custom one
// to bring better experience for Create React App users. You can replace
// the line below with these two lines if you prefer the stock client:
// require.resolve('webpack-dev-server/client') + '?/',
// require.resolve('webpack/hot/dev-server'),
isEnvDevelopment && require.resolve('react-dev-utils/webpackHotDevClient'),
// Finally, this is your app's code:
paths.appIndexJs
// We include the app code last so that if there is a runtime error during
// initialization, it doesn't blow up the WebpackDevServer client, and
// changing JS code would still trigger a refresh.
].filter(Boolean),
paths.appIndexJs指向的正是src/index.html文件;
此时我们运行程序就可以看到:
由于create-creat-app创建的项目,在webpack.config.js中配置了webpack-dev-server热加载:
可以看到如果当前运行在开发环境下,我们项目将会使用自定义的webpackDevServer客户端,当我们文件发生变化时,该客户端将会通知WebpackDevServer服务器,然后进行页面刷新。
我们可以实时改变App组件输出的内容,然后查看浏览器的变化。此外,如果我们想使用默认的WebpackDevServer客户端,可以取消下面代码注释:
require.resolve('webpack-dev-server/client') + '?/',
require.resolve('webpack/hot/dev-server'),
这种页面的刷新有个缺点,每次刷新都会清空我们组件的状态值。因此,我们需要使用局部热刷新技术,这个后面我们会介绍 react-hot-loader 工具。
至此,我们的准备工作就完成了,下一节将会介绍前端框架的搭建。
五、样式配置
1、CSS Modules
在[email protected] 及更高版本,项目使用.module.css 文件命名约定支持 CSS Modules 。 CSS Modules 允许通过自动创建格式唯一的classname 来确定 CSS 的作用域,从而避免污染全局样式。CSS Modules 允许你在不同的文件中使用相同的 CSS classname,而无需担心命名冲突。
由create-react-app创建的项目,在webpack.config.js中指定了匹配各种样式文件的正则表达式:
// style files regexes
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;
(1).针对.css文件,样式处理器配置如下:
// "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies.
// "style" loader turns CSS into JS modules that inject