最近学习react.js,发现项目框架除了使用的js库不一样(vue.js、react.js),配置基本上是大同小异的css
进入根目录,初始化项目html
cd reactProject
npm init -y // -y是采用默认配置
复制代码
此时目录出现package.json文件前端
在根目录下新建src文件夹,在src下暂时新建名为index的js文件做为入口文件vue
根目录下建立一个index.html,做为入口页面node
下载webpack时你可能会出现无限下载webpack-cli的问题,这是由于你没有先全局安装webpack和webpack-cli的缘由react
// webpack4.X开始webpack-cli被提出来做为一个独立的包了
// 在下载webpack同时也要下载webpack-cli,且必须同时下载不然会报错,由于版本不匹配
cnpm install webpack-cli webpack --save-dev
复制代码
webpack默认只能打包js模块,它能够将你写的多个js模块打包成一个js文件,最后在入口页面引入它webpack
webpack4开始默认大于配置,换句话说能够不用再引入一个配置文件来打包项目,所以他有不少默认值web
默认入口文件是src下的index.js,输出为dist目录下的main.js(假如没有dist目录会自动建立)npm
可是它仍然是高配置的,假如须要咱们只需在项目根目录下新建webpack.config.js来进行一切的配置json
相比于webpack4以前的版本,它的配置项多出一个mode选项,可选值为"development" 或 "production"(默认),它们的区别就是development打包输出的文件不是压缩版本的
react和vue不一样的是,react使用两个包协同工做
cnpm install react react-dom --save-dev
复制代码
index.js中
// index.js
import React from 'react'
// 这个包名必须这样写
import ReactDOM from 'react-dom'
/* *createElement: 建立虚拟dom元素 * 第一个参数为标签类型 * 第二个参数为标签属性对象 * 剩余参数皆为参数为子节点 */
const dom = React.createElement("h1",{id: "test"},"hello react")
// render函数是将虚拟dom插入目标容器Target container
ReactDOM.render(
dom,
document.getElementById("root")
)
复制代码
index.html中
// index.html
<div id ="root"></div>
复制代码
页面中会看到hello react的字样,审查元素以下
<div id="root"><h1 id="test">hello react</h1></div>
复制代码
这说明咱们的准备工做都成功完成了
每次写完新的内容要想看到效果,就必须使用webpack进行打包,咱们更但愿当代码改变时自动打包编译
webpack-dev-server能够帮咱们作到!
cnpm i webpack-dev-server --save-dev
复制代码
咱们不能像使用webpack命令同样使用webpack-dev-server命令,由于webpack-dev-server是局部安装的,而令行里只能使用全局安装的包,使用局部安装的包,咱们须要使用在package.json中配置scripts
// package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server --hot"
},
复制代码
而后再命令行使用npm run dev
npm run dev
复制代码
注意看下面的节选的代码
npm run dev
> vueproject@1.0.0 dev C:\myProject\reactProject
> webpack-dev-server
i 「wds」: Project is running at http://localhost:8080/
i 「wds」: webpack output is served from /
i 「wds」: Content not from webpack is served from C:\myProject\reactProject
i 「wdm」: Hash: e70fb3ae9bf074915cad
Version: webpack 4.35.0
复制代码
从这里咱们知道两件事: 首先,咱们的项目运行在本机8080端口,其次webpack的output输出在根目录下,因此记得修改index.html中引入main.js的路径,不然你是看不到新的效果的
可是咱们在根目录下并无看到这个文件,这是由于它被放在内存中(这样的读写速度快),而不是磁盘中,另外咱们还能够修改端口,甚至能够在编译完成后自动打开浏览器
它具体的配置能够是在webpack的devServer项
devServer:{
host: '127.0.0.1',
port: 8081,
open: true
}
复制代码
也能够是在cli里,这是最暴力的方式,可是端口仍是放在devServer里,方便之后项目的配置
// package.json
"scripts": {
"dev": "webpack-dev-server --open --port 30000"
},
复制代码
既然将main.js放在内存中能够加快读写速度,那是否是把页面放在内存中能够进一步加快读写速度了?
答案是确定的!使用html-webpack-plugin就能够作到
cnpm i html-webpack-plugin --save-dev
复制代码
// webpack.config.js
const htmlWebpackPlugin = require('html-webpack-plugin')
...
plugins: [
new htmlWebpackPlugin({
template: path.join(__dirname, "./index.html"),
filename: "index.html"
})
],
复制代码
上面的代码是根据磁盘中的index.html在内存中生成一个index.html,咱们在浏览器中审查页面发现会多一个script标签,这是插件自动将内存中的main.js加入到内存页面中了,因此咱们这是应该删除手动添加的script标签
// index.html
<body>
<div id="app"></div>
<!--删除或者注释掉 <script src="./main.js"></script> -->
</body>
复制代码
如今它已经能够本身跑起来并自动监听变化作出反应了
虽然开起来已经很完美了,可是像前面面那样写react虚拟dom老是以为很复杂,做为前端工程师,咱们更但愿写的dom就是这样的,而后把它和以前同样插入
const dom = <h1 id="test">hello react</h1>
ReactDOM.render(
dom,
document.getElementById("root")
)
复制代码
这彻底是能够的,上面的写法就是react的扩展语法jsx,使用jsx语法必须使用babel-loader
有了前面文章的经验,我发现若是如今下载babel-loader最好使用下面的形式,由于babel已经更新到7.x.x了,写法和以前的版本有很大差别,不然老是会出现一些版本不兼容的错误
//下载loader加载器
cnpm i @babel/core babel-loader --save-dev
//下载插件
cnpm i @babel/plugin-transform-runtime --save-dev
//下载预设
cnpm i @babel/preset-env @babel/preset-react --save-dev
复制代码
babel的两种使用方法前面已经说过了,这里再简单的说说官网给出的别的简单方法
第一种方法,在rules中配置babel-loader同时提供options选项
// 第一种写法。
//除了基本的配置test外,可使用options,里面必须有presets和plugins两个选项
// presets是预设的babel语法转换规则,这里除了使用最新的规则外仍是用了针对react的jsx转换规则
// plugins是指明使用的插件
module: {
rules: [
{
test: /\.js|jsx$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
plugins: ["@babel/plugin-transform-runtime"]
}
}
}
]
},
复制代码
第二种方法根目录新建.babelrc文件,格式同json
{
presets: ["@babel/preset-env", "@babel/preset-react"],
plugins: ["@babel/plugin-transform-runtime"]
}
//它会自动识别到这个文件
//此时能够删掉第一种方法中的options选项
复制代码
第三种方法在package.json中添加babel节点
{
"name": "my-package",
"version": "1.0.0",
"babel": {
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": ["@babel/plugin-transform-runtime"]
}
}
复制代码
第四种方法是根目录新建.babelrc.js 配置和前面都同样,只是可用js编写
const presets = ["@babel/preset-env", "@babel/preset-react"];
const plugins = ["@babel/plugin-transform-runtime"];
// 这种写法的好处是你能够调用node API
if (process.env["ENV"] === "prod") {
plugins.push(...);
}
module.exports = { presets, plugins };
复制代码
固然还有cli方法,或者选择转换node_modules目录的babel.confog.js的方法,但都是比较复杂或者冷门的
在src下新建了一个css样式表文件夹,里面写了本身针对本身组件的样式,而后在须要的jsx文件中引入它,像我这样
/* css/index.css文件 */
.test{
color: green
}
复制代码
//在index.jsx文件中引入样式
import React from "react";
import "@/css/index.css"
export default function Index() {
return <div className="test" id="index">index page</div>;
}
//在login.jsx中不引入样式,可是添加class
import React from "react";
export default class Login extends React.Component {
render() {
// 由于class是js的关键字,因此jsx中使用className做为html的class
return <div className="test">login page</div>;
}
}
复制代码
这时候会报错,提示使用合适的loader
和vue同样要使用样式表必须使用loader,由于它们都是jsx语法生成虚拟dom的,而jsx没法解析样式表
cnpm i style-loader css-loader --save-dev
复制代码
下载完以后和vue项目同样配置文件
rules: [
...
{
test: /\.css$/,
use: ["style-loader","css-loader"]
}
]
复制代码
虽然这时候可使用样式了可是,你会发现你没有引入样式的login组件页面也是绿色字体了
好在css-loader能够提供模块化功能,咱们只需以下改动
rules: [
...
{
test: /\.css$/,
// 这种写法和url带参数很相似,这是开启模块化的意思
use: ["style-loader","css-loader?modules"]
}
]
复制代码
此时咱们的引入css样式须要一个参数去接收css暴露出来的模块(固然这是css-loader的功能)
//在index.jsx文件中引入样式
import React from "react";
import indxCss from "@/css/index.css"
console.log(indxCss) // => {test: "q7KCiLIWvHKVJp6HMfV2y"}
export default function Index() {
return <div className={indxCss.test} id="index">index page</div>;
}
复制代码
同时说个有意思的事,css-loader除了modules参数外,还有不少参数 若是你不喜欢随机的字符串作样式的标识,能够设置localIdentName参数,它是如下方式的组合
rules: [
...
{
test: /\.css$/i,
// 下面这种写法是老版本的写法,会一直报错无效的版本,别问我是怎么知道的,webpack官网没有提示
//use: ["style-loader","css-loader?modules"],
// 新版本3.0.0是这样的
// 去css-loader的npm官网才能看到这种写法
use: [
{ loader: "style-loader" },
{
loader: "css-loader",
options: {
modules: {
localIdentName: "[path][name]-[local]-[hash:base64:5]"
}
}
}
]
}
]
复制代码
虽然如今看上去是完美的,可是有个问题是假如如今引入第三方库,它也是css文件,也会被模块化的,但咱们但愿它是全局有效的,比较好的作法就是第三方库采用css样式,而本身的样式启用scss或者less,因此你得安装它们的loader
cnpm i less-loader --save-dev
复制代码
添加loader
rules: [
...
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
test: /\.less$/i,
use: [
{ loader: "style-loader" },
{
loader: "css-loader",
options: {
modules: {
localIdentName: "[path][name]-[local]-[hash:base64:5]"
}
}
},
{loader: "less-loader"}
]
}
]
复制代码
若是在样式中添加以下样式
.test{
background-image: url(../imgs/11.jpg)
}
复制代码
会发现jsx也没法处理图片url的,因此得添加loader去处理这些
url-loader内部使用了file-loader,因此两个loader要同时下载
cnpm i url-loader file-loader --save-dev
复制代码
基本的使用以下
module: {
rules: [
...
{
test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)$/,
loader: "url-loader"
}
]
},
复制代码
这个和css-loader设置同样
module: {
rules: [
{
test: /\.(jpg|png|jpeg)$/,
loader: "url-loader",
options: {
limit: 8000, // 当文件字节大小超过限定值时触发后面的设置
name: "[hash:8]-[name].[ext]" // 这是在原先的名称和后缀名前加了八位的哈希码
}
}
]
},
复制代码
目前基本的功能都有了,可是仍是不够完美,下期将会引入react-router,对业务进行封装。从目前来看,无论vue项目框架仍是react框架,有极大的类似之处,学了vue学react就简单多了,并且这是学习react对vue的理解也上升了一个层次。
若是你也作到这里相信你也会有这种感觉
努力、奋斗