共计 3474 个字符,预计需要花费 9 分钟才能阅读完成。
背景
还是之前的那个项目,做完国际化没多久,还没来得及划水,又有新的活了 — 移动端的兼容。考虑到后期的复杂度,需要做两套资源。具体的目标是:同一个 URL,PC 打开就显示 PC 的那一套,M 端打开就显示 Mobile 的页面。create-react-app 脚手架本身不支持多入口,需要改造,今天下午研究了一下,改造了一波,基本达到了预期,在这里简单把经验总结分享下。
先睹为快
Mobile:
PC:
输出之后的文件,相比之前的 index.html,多了一个额外的 mobile.html.
最终的源代码目录:
具体的改造步骤如下:
Steps
step1: Eject
在下之前图方便,直接用了 create-react-app,现在需要更改配置,需要弹出默认配置:
在终端执行:yarn eject.
step2: 修改 webpack config
原本的 webpack.config.dev.js:
entry: [
require.resolve(‘react-dev-utils/webpackHotDevClient’),
require.resolve(‘./polyfills’),
require.resolve(‘react-error-overlay’),
paths.appIndexJs,
],
output: {
path: paths.appBuild,
pathinfo: true,
filename: ‘static/js/bundle.js’,
chunkFilename: ‘static/js/[name].chunk.js’,
publicPath: publicPath,
devtoolModuleFilenameTemplate: info =>
path.resolve(info.absoluteResourcePath),
},
需要修改为:
entry: {
index: [
require.resolve(‘./polyfills’),
require.resolve(‘react-dev-utils/webpackHotDevClient’),
paths.appIndexJs,
],
mobile: [
require.resolve(‘./polyfills’),
require.resolve(‘react-dev-utils/webpackHotDevClient’),
paths.appSrc + “/mobile/index.js”,
]
},
output: {
pathinfo: true,
filename: ‘static/js/[name].bundle.js’,
chunkFilename: ‘static/js/[name].chunk.js’,
publicPath: publicPath,
devtoolModuleFilenameTemplate: info =>
path.resolve(info.absoluteResourcePath).replace(/\\/g, ‘/’),
},
可能需要注意的几点:
entry 从原来的数组扩展为对象,每个 key 代表一个入口。
output 中的 filename 要区分输出名,可增加 [name] 变量,这样会根据 entry 分别编译出每个 entry 的 js 文件。
这样你就可以在 src 目录下新起一个民目录开发新的 SPA:
step3: 生成多个 html 入口文件
Webpack 配置多入口后,只是编译出多个入口的 Js,入口的 HTML 文件也需要配置,可以用 HtmlWebpackPlugin 来生成。
webpack.config.dev.js 原配置:
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin({
inject: true,
chunks: [“index”],
template: paths.appHtml,
}),
需要加多一个配置,改成:
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin({
inject: true,
chunks: [“index”],
template: paths.appHtml,
}),
new HtmlWebpackPlugin({
inject: true,
chunks: [“mobile”],
template: paths.appHtml,
filename: ‘mobile.html’,
}),
每调一次 HtmlWebpackPlugin 生成一次 HTML 页面,这里有两个,所以就会多增加一个 mobile.html 节点。
chunks:指明哪些 webpack 入口的 js 会被注入到这个 HTML 页面。如果不配置,则将所有 entry 的 JS 文件都注入 HTML。
filename: 指明生成的 HTML 路径,如果不配置就是 dist/index.html。mobile 配置了新的 filename,避免与第一个入口相互覆盖。
template:指定模版,我这里因为用的这两个模版都一样,所以就指定的同一个 appHtml, 如有特殊需求,就新建一个 html 文件,在 template 字段里引用即可。
Step4: 配置 webpack Dev Server
上述配置做完后,理论就可以打包出多入口的版本;但使用 npm start 启动后,发现无论输入 /index.html 还是 /mobile.html,好像都是和原来 /index.html 显示一样的内容。
甚至输入显然不存在的 /xxxx.html,也显示为 /index.html 的内容。
这种现象,初步判断是 HTTP 服务器把所有请求重定向到了 /index.html。
对于单页应用,这种做法是没有问题的(本来就一个页面), 但我们新增的 /mobile.html 就可以访问到了。
参考官方文档 The historyApiFallback option,发现是 webpack dev server 的问题,还要额外做一些配置,需修改 webpackDevServer.config.js:
原配置:
historyApiFallback: {
// Paths with dots should still use the history fallback.
// See https://github.com/facebookincubator/create-react-app/issues/387.
disableDotRule: true,
},
修改为:
historyApiFallback: {
// Paths with dots should still use the history fallback.
// See https://github.com/facebookincubator/create-react-app/issues/387.
disableDotRule: true,
// 指明哪些路径映射到哪个 html
rewrites: [
{from: /^\/mobile.html/, to: ‘/dist/mobile.html’},
]
},
增加的 rewrites 节点,特别对 /admin.html 这个 URL 重定向为 /dist/mobile.html 页面(也就是 HtmlWebpackPlugin 输出的 HTML 文件路径),这样 /mobile.html 就可以正常访问了。
至此,dev 环境的多入口问题就解决了。
step5: Prod 环境配置
prod 环境,比 dev 环境更简单。由于不存在 webpack Dev Server,直接在 config/webpack.config.prod.js 同理做 2 和 3 步骤即可。
这时候你就可以通过手动修改 URl 来访问了:
路由相关
到这,已经可以手动修改 URL 来访问 pc 和 mobile 的页面了。还有一个问题没有解决:
URL 最后肯定是不能给你手动改来改去的,需要根据设备的情况自己判断,这里有两个思路:
1: 配置 Engix 的路径的时候,加多一个 alias 的映射。2: 前端根据 UA 自行配置。
我这为了快速出效果,简单搞了一下,具体代码如下:
这样,不用手动修改 URL 也能根据 UA 自动显示不同的页面了, 具体的效果图在文章开头的先睹为快中。
其他
上面的路由就为了简单的出个效果,比较粗暴,仅供参考。
结语
以上就是全部的细节了,达到了预期的效果,但是也有很大优化空间。等后面一波需求做完了,再来做补充吧。:P
End。
参考资料:
https://medium.com/a-beginner…
http://imshuai.com/create-rea…