单页面的应用是目前前端应用的主流方向,react、vue等前端框架在单页面应用上都相对比较适用。但是多页面应用在项目的也必不可少,企业的门户网站因需要百度推广,更加适合用多页面应用来开发。本文将介绍运用create-react-app脚手架来搭建一个简单实用的多页面项目框架。
1.初始化项目
创建create-react-app脚手架这边不过多叙述,react开发人员应该都会构建,构建成功后执行以下命令初始化webpack配置;
yarn eject 或者 npm run eject
执行完毕后项目的根目录会自动创建config文件夹,里面的文件即初始化的webpack配置文件。
2.整理src目录文件
- 删除src文件夹内多余的文件
只需要保留index.js和App.jsx文件,在打包时可能用到pwa的serviceWorker,因而也保留ServiceWorker.,js文件,删除其他多余文件。
- 新建pages文件夹,用于存放多页面的各个页面应用
pages文件夹内的每一个文件目录即为一个页面应用,不能乱存放文件和文件目录,在pages文件夹内新建home和note文件,即两个页面应用,将之前src保留的index.js和App.jsx分别拷贝到home和note目录。
- 必不可少用到redux,修改index.js的文件
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { createStore, compose, applyMiddleware } from 'redux'
import { ConfigProvider } from 'antd'
import thunk from 'redux-thunk'
import reducer from '../../store/reducer'
import zhCN from 'antd/es/locale/zh_CN'
import * as serviceWorker from '../../serviceWorker'
import App from './App'
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)))
ReactDOM.render(
<Provider store={store}>
<ConfigProvider locale={zhCN}>
<App />
</ConfigProvider>
</Provider>,
document.getElementById('root')
)
serviceWorker.unregister()
3.修改paths.js配置页面的路径入口
进入config文件目录内的paths.js文件,添加以下代码,配置页面的路径入口;
const glob = require('glob');
// 获取指定路径下的入口文件
function getEntries (globPath) {
const files = glob.sync(globPath),
entries = {};
files.forEach(function (filepath) {
const split = filepath.split('/');
const name = split[split.length - 2];
entries[name] = './' + filepath;
});
return entries;
}
const entries = getEntries('src/pages/**/index.js');
function getIndexJs () {
const indexJsList = [];
Object.keys(entries).forEach((name) => {
const indexjs = resolveModule(resolveApp, `src/pages/${name}/index`)
indexJsList.push({
name,
path: indexjs
});
})
return indexJsList;
}
const indexJsList = getIndexJs()
在module.exports导出对象里添加上述定义的entries入口
module.exports = {
dotenv: resolveApp('.env'),
appPath: resolveApp('.'),
appBuild: resolveApp('build'),
appPublic: resolveApp('public'),
appHtml: resolveApp('public/index.html'),
appIndexJs: indexJsList,
appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'),
appTsConfig: resolveApp('tsconfig.json'),
appJsConfig: resolveApp('jsconfig.json'),
yarnLockFile: resolveApp('yarn.lock'),
testsSetup: resolveModule(resolveApp, 'src/setupTests'),
proxySetup: resolveApp('src/setupProxy.js'),
appNodeModules: resolveApp('node_modules'),
publicUrlOrPath,
entries // 添加入口对象
};
4.修改webpack.config.js文件
(1)配置入口entry
在return之前定义entry变量,遍历上述paths内的appIndexJs
const entry = {}
paths.appIndexJs.forEach(e => {
entry[e.name] = [
isEnvDevelopment &&
require.resolve('react-dev-utils/webpackHotDevClient'),
e.path
].filter(Boolean)
});
然后将配置中return的entry改成定义的entry变量。
(2)修改出口output
将output中的filename和chunkFilename修改下,添加page的路径
// 修改前
filename: isEnvProduction
? 'static/js/[name].[contenthash:8].js'
: isEnvDevelopment && 'static/js/bundle.js',
// TODO: remove this when upgrading to webpack 5
futureEmitAssets: true,
// There are also additional JS chunk files if you use code splitting.
chunkFilename: isEnvProduction
? 'static/js/[name].[contenthash:8].chunk.js'
: isEnvDevelopment && 'static/js/[name].chunk.js',
// 修改后
filename: isEnvProduction
? 'static/js/[name]/[name].[contenthash:8].js'
: isEnvDevelopment && 'static/js/[name]/[name].bundle.js',
// TODO: remove this when upgrading to webpack 5
futureEmitAssets: true,
// There are also additional JS chunk files if you use code splitting.
chunkFilename: isEnvProduction
? 'static/js/[name]/[name].[contenthash:8].chunk.js'
: isEnvDevelopment && 'static/js/[name]/[name].chunk.js',
(3)修改plugins
HtmlWebpackPlugin插件的主要作用是生成创建html的文件,配置多个HtmlWebpackPlugin可以生成多页面的html文件入口,将之前配置单页面的HtmlWebpackPlugin删除,添加如下遍历entry的生成多页面的入口
// Generates an `index.html` file with the <script> injected.
...Object.keys(paths.entries).map((name) => {
return new HtmlWebpackPlugin(
Object.assign(
{},
{
inject: true,
chunks: [name],
template: paths.appHtml,
filename: name + '.html',
},
isEnvProduction
? {
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}
: undefined
)
)
}),
(4)注释ManifestPlugin部分代码
// new ManifestPlugin({
// fileName: 'asset-manifest.json',
// publicPath: paths.publicUrlOrPath,
// generate: (seed, files, entrypoints) => {
// const manifestFiles = files.reduce((manifest, file) => {
// manifest[file.name] = file.path;
// return manifest;
// }, seed);
// const entrypointFiles = entrypoints.main.filter(
// fileName => !fileName.endsWith('.map')
// );
// return {
// files: manifestFiles,
// entrypoints: entrypointFiles,
// };
// },
// }),
(5)更改校验文件是否存在的代码
修改scripts目录下的build.js和start.js文件的校验代码
// 原来代码
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
}
// 修改后的代码
if (!checkRequiredFiles([paths.appHtml, ...paths.appIndexJs.map(e => e.path)])) {
process.exit(1);
}
成果
1.访问路径
http://localhost:3000/home.html
http://localhost:3000/note.html
2.添加页面
添加页面只要在pages目录内添加新页面的目录文件即可。
相应项目的git后续上传