配置一个最基本的 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.jsresolve.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!