配置一个最基本的 React 项目,大概分为一下几个部分:
express
快速构建一个服务器/dist
- bundle.js // 打包后的js文件
- bundle.map.js // source-map文件
/entry
- index.jsx // React项目住入口
/node_modules
/pages
- App.jsx
- app.less
/views
- index.html
.babelrc
app.js
package-lock.json
package.json
webpack.config.js
最终配置如下:
const path = require('path');
module.exports = () => ({
mode: 'development',
entry: {
app: path.resolve(__dirname, './entry/index.jsx')
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
resolve: {
extensions: ['.jsx', '.js']
},
module: {
rules: [
{
test: [/.js$/, /.jsx$/],
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}, {
test: /\.less$/,
use: [{
loader: 'style-loader'
}, {
loader: 'css-loader'
}, {
loader: 'less-loader'
}]
}
]
},
watch: true,
devtool: 'source-map'
})
各方面解释如下:
./entry/index.jsx
./dist
,文件名称为bundle.js
resolve.extensions
为['.jsx', '.js']
,从而在文件引入的时候可以不带上后缀,如import App from '../pages/App'
,此时../pages/App
会按照../pages/App.jsx
的方式去查找,若找不到,再按照 js 的后缀去查找,再找不到就会报错首先是对于.js
和.jsx
的文件,采用babel-loader
进行 babel 编译。其主要目的是转义jsx
语法和es6
及其以上的语法,具体 babel 配置见下面 babel 配置方面
对于 less 文件,依次采用了less-loader
、css-loader
和style-loader
进行处理,这三个 loader 的作用如下:
less-loader
:将 less 语法编译为 csscss-loader
:css-loader 的使用,允许你在 less 文件或 css 文件中采用@import
和url()
加载其他文件,与采用import
和require
类似,css-loader 回去解析它们style-loader
:将 css 文件已<style>
标签的形式插入到html 文件的 DOM 中,从而使样式生效babel 的配置,主要有两方面作用:
jsx
语法es6
及以上的语法为 es5,使其能够在低版本浏览器中运行最终的配置文件如下:
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"forceAllTransforms": true
}
],
[
"@babel/preset-react"
]
],
"plugins": [
[
"@babel/plugin-transform-runtime",
]
]
}
使用到的 preset 及 plugins 解释如下:
@babel/preset-env
:根据目标运行环境来转化es6及以上代码,使其能够在目标环境中运行。目标环境可以通过.browserlistrc
或package.json
中的target
字段指定,若未指定,则采用默认配置
"useBuiltIns": "usage"
,若代码中采用了 es6及以上的高级功能,babel 会自动引入对应的polyfill
@babel/preset-react
,转义 React 的 jsx
语法的相关内容@babel/plugin-transform-runtime
:生成沙箱环境,是的各类 polyfill 不影响全局变量,并减少包的体积./entry/index.jsx
:import React from 'react';
import ReactDOM from 'react-dom';
import App from '../pages/App';
ReactDOM.render(<App />, document.getElementById('root'));
./pages/App.jsx
:import React from 'react';
import './app.less';
const App = ()=> (
<div className="hello">Hello world!</div>
)
export default App;
配置后之后,使用 webpack 打包,即可看到./dist
文件夹中生成了bundle.js
文件。
const express = require('express');
const fs = require('fs');
const app = express();
const PORT = process.env.PORT || '3100';
app.use(express.static('dist'));
app.get('/', async (req, res) => {
const page = fs.readFileSync('./views/index.html');
res.end(page);
})
app.listen(PORT, () => {
console.log(`Server has been listening on ${PORT}`);
})
./views/index.html
:<!DOCTYPE html>
<html>
<head>
<title>common-react-config</title>
<meta charset="UTF-8">
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="/bundle.js"></script>
</body>
</html>
package.json
中加入start
脚本"start": "webpack & nodemon app.js",
执行npm start
即可在localhost:3100
中看到Hello world!
localhost:30000
,请求进入app.js
中后,后端会读取./views/index.html
并返回给前端app.get('/', async (req, res) => {
const page = fs.readFileSync('./views/index.html');
res.end(page);
})
<script>
请求bundle.js
文件<script type="text/javascript" src="/bundle.js"></script>
bundle.js
的请求,会在服务器端静态服务器处找到bundle.js
文件,并返回此文件app.use(express.static('dist'));
bundle.js
文件后,执行对应 js,并渲染出Hello world!