webpack4+react16 多页面架构
webpack 在单页面打包上应用广泛, 以 create-react-App 为首的脚手架众多, 单页面打包通常指的是将业务 JS,CSS 打包到同一个 html 文件中, 整个项目只有一个 HTML 文件入口, 但也有许多业务需要多个页面不同的入口, 比如不同的 h5 活动, 或者需要支持 seo 的官方网站, 都需要多个不同的 HTML.webpack-react-multi-page 架构让你可以在多页面在项目开发中自动化打包新创建页面并保证每个页面都可以热更新 ,build 打包后有清晰的文件层次结构.
概览
key | value |
---|---|
名称 | webpack+react 多页面架构 |
描述 | 简单易用的多页面自动化开发架构 |
开发者 | leinov |
发布日期 | 2018-11-07 |
版本 | 2.0 |
仓库 | github 地址 https://github.com/leinov/webpack-react-multi-page |
特性
支持多页面同时热加载开发
自动识别新创建页面
每个页面生成个性化信息
分类打包
灵活扩展
安装 & 使用
- // clone
- Git clone Git@GitHub.com:leinov/webpack-react-multi-page.Git
- // 安装依赖包
- NPM install
- // 开发
- NPM run dev
- // 编译打包
- NPM run build
- // 启动生产页面
- NPM start
新创建页面在 src 下添加文件夹并创建 pageinfo.JSON 然后 NPM run dev 即可
- |-- src
- |-- index/
- |-- page2/
- |-- index.JS
- |-- pageinfo.JSON
项目架构
技术使用
react16
webpack4
HTML-webpack-plugin 生成 HTML 文件
mini-CSS-extract-plugin CSS 分离打包
uglifyjs-webpack-plugin JS 压缩
optimize-CSS-assets-webpack-plugin CSS 压缩
es6
babel
node
opn 打开浏览器
compression 开启 gzip 压缩
express
fs
Git
目录结构
- |-- webpack-react-multi-pages // 项目
- |-- dist // 编译生产目录
- |-- index
- |-- index.CSS
- |-- index.JS
- |-- about
- |-- about.CSS
- |-- about.JS
- |-- images
- |-- index.HTML
- |-- about.HTML
- |-- node_modules //node 包
- |-- src // 开发目录
- |-- index //index 页面打包入口
- |-- images/
- |-- JS
- |-- App.JS// 业务 JS
- |-- index.Sass
- |-- index.JS // 页面 JS 入口
- |-- about //about 页面打包入口
- |-- images/
- |--JS
- |-- App.JS// 业务 JS
- |-- about.Sass
- |-- about.JS // 页面 JS 入口
- |-- template.HTML // HTML 模板
- |-- style.Sass // 公共 Sass
- |-- webpackConfig // 在 webpack 中使用
- |-- getEntry.JS // 获取入口
- |-- getFilepath.JS //src 下需要打包页面文件夹
- |-- htmlconfig.JS // 每个页面 HTML 注入数据
- |-- package.JSON
- |-- .gitignore
- |-- webpack.config.JS //webpack 配置文件
- |-- www.JS // 生产启动程序
- wiki
webpack 打包单页面应用
webpack 在单页面打包上应用广泛, 以 create-react-App 为首的接触脚手架众多, 单页面打包通常指的是将业务 JS,CSS 打包到同一个 HTML 文件中, 整个项目只有一个 HTML 文件入口
webpack 单页面打包配置
- webpack.config.JS
- module.exports = (env, argv) => ({
- entry: ".src/index.js",
- output: {
- path: path.join(__dirname, "dist"),
- filename: "bundle.js"
- },
- module: {
- rules: [
- ...
- ],
- },
- plugins: [
- new HtmlWebpackPlugin({
- title: "首页",
- filename:"index.html",
- favicon:"",
- template: "./src/template.html",
- })
- ]
- });
这样就可以在 dist 文件夹下打包出一个下面这样的文件
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <title>
- 首页
- </title>
- <body>
- <div id="root">
- </div>
- <script type="text/javascript" src="bundle.js">
- </script>
- </body>
- </HTML>
webpack 多页面打包配置
webpack 的 entry 支持两种种格式
打包单个文件
- module.exports = {
- entry: '.src/file.js',
- output: {
- path: path.resolve(__dirname, 'dist'),
- filename: 'bundle.js'
- }
- };
这样就会在 dist 下打包出一个 bundle.JS
打包出多个文件
- module.exports = {
- entry: {
- index:"./src/index.js",
- about:"./src/about.js"
- },
- output: {
- path: path.resolve(__dirname, 'dist'),
filename: '[name].js' index.JS,about.JS 这两个文件
}
};
上面在 dist 下打包出两个与 entry 属性名对应的 JS 文件
将每个 JS 挂载到相应的 HTML 文件上
这里我们需要用到 HTML-webpack-plugin 这个 webpack 插件, 每添加一个页面就需要在 plugins 添加一个 new HtmlWebpackPlugin({....})
- const HtmlWebpackPlugin = require("html-webpack-plugin");
- module.exports = (env, argv) => ({
- entry: {
- index:"./src/index.js",
- about:"./src/about.js"
- },
- output: {
- path: path.resolve(__dirname, 'dist'),
filename: '[name].js' index.JS,about.JS 这两个文件
- }
- ....// 其他配置
- plugins: [
- new HtmlWebpackPlugin(
- {
- filename:"index.html",// 生成的 index.HTML
- template: "./src/template.html",}) // 模板
- chunks:["index"]
- }),
- new HtmlWebpackPlugin(
- {
- filename:"about.html",// 生成的 index.HTML
- template: "./src/template.html",}) // 模板
- chunks:["index"]
- })
- ]
- })
HTML-webpack-plugin 会通过 template.HTML 模板生成对应的 filename 名的 HTML 文件, 并一并打包到 output 中对应的文件夹下, 注意, 在没有特殊配置的情况下所有打包的文件都是对应到 output 中 path 这个目录下, 也包括 HTML. 这里的 chunks 需要注意, 它是确定该 HTML 需要引入哪个 JS, 如果没写的话, 默认会引出所有打包的 JS, 当然这不是我们想要的.
上面的配置最终可以在 dist 下打包出下面的文件结构
- |-- dist
- |-- index.JS
- |-- about.JS
- |-- index.HTML // 内挂载 index.JS
- |-- about.HTML // 内挂载 about.JS
通过上面这样的配置, 再加上 devServer, 我们已经可以实现多页面的配置开发了, 但这样很不智能, 因为你每增加一个页面, 就要在 wepback 里面配置一次, 会非常繁琐, 所以我们来优化下, 让我们只专注于开发页面, 配置交给 webpack 自己.
webpack 多页面配置优化
我们再看下 src 下面的文件结构
- |-- src
- |-- index
- |-- App.JS
- |-- index.SCSS
- |-- index.JS
- |-- about
- |-- App.JS
- |-- index.SCSS
- |-- index.JS
src 下面每个文件夹对应一个 HTML 页面的 JS 业务, 如果我们直接把文件夹对应入口 JS 找到并把他们合并生成对应的 entry, 那是不是就不用手动写 entry 了呢, 是的!
遍历文件目录
- /* eslint-env node */
- /**
- * @file: getFilePath.JS 遍历文件目录
- * @author: leinov
- * @date: 2018-10-11
- */
- const fs = require("fs");
- /**
- * [遍历某文件下的文件目录]
- *
- * @param {String} path 路径
- * @returns {Array} ["about","index"]
- */
- module.exports = function getFilePath(path){
- let fileArr = [];
- let existpath = fs.existsSync(path); // 是否存在目录
- if(existpath){
- let readdirSync = fs.readdirSync(path); // 获取目录下所有文件
- readdirSync.map((item)=>{
- let currentPath = path + "/" + item;
- let isDirector = fs.statSync(currentPath).isDirectory(); // 判断是不是一个文件夹
- if(isDirector && item !== "component"){ // component 目录下为组件 需要排除
- fileArr.push(item);
- }
- });
- return fileArr;
- }
- };
比如在 src 下有 index 页面项目, about 项目 遍历结果为 ["index","about"];
遍历生成打包入口数组
- /* eslint-env node */
- /**
- * @file: getEntry.JS 获取 entry 文件入口
- * @author: leinov
- * @date: 2018-10-11
- * @update: 2018-11-04 优化入口方法 调用 getFilePath
- */
- const getFilePath = require("./getFilepath");
- /**
- * [获取 entry 文件入口]
- *
- * @param {String} path 引入根路径
- * @returns {Object} 返回的 entry { "about/aoubt":"./src/about/about.js",...}
- */
- module.exports = function getEnty(path){
- let entry = {};
- getFilePath(path).map((item)=>{
- /**
- * 下面输出格式为 {"about/about":"./src/aobout/index.js"}
- * 这样目的是为了将 JS 打包到对应的文件夹下
- */
- entry[`${item}/${item}`] = `${path}/${item}/index.js`;
- });
- return entry;
- };
这里我们使用 getFilepath 获取的数组, 在获取到每个目录下的 JS 文件, 组合成一个 JS 入口文件的如下格式的对象.
- {
- "index/index":"./src/index/index.js",
- "about/about":"./src/about/index.js"
- }
在 webpack 中使用 getEntry
- const getEntry = require("./webpackConfig/getEntry");
- const entry = getEntry();
- module.exports = (env, argv) => ({
- entry: entry,
- })
这样我们就自动获取到了 entry
HTML-webpack-plugin 自动配置
因为每个页面都需要配置一个 HTML, 而且每个页面的标题, 关键字, 描述等信息可能不同, 所以我们在每个页面文件夹下创建一个 pageinfo.JSON, 通过 fs 模块获取到 JSON 里信息再遍历到对应得 HTML-webpack-plugin 中生成一个 HTML 插件数组.
index/pageinfo.JSON 生成 index.HTML 页面信息
- {
- "title":"首页",
- "keywords":"webpack 多页面"
- }
about/pageinfo.JSON 生成 about.HTML 页面信息供
- {
- "title":"关于页面",
- "keywords":"webpack 多页面关于页面"
- }
通过 fs 遍历读取并生成 HtmlWebpackPlugin 数组供 webpack 使用
遍历 HTML 插件数组
- /**
- * @file htmlconfig.JS 页面 HTML 配置
- * @author:leinov
- * @date: 2018-10-09
- * @update: 2018-11-05
- * @use: 动态配置 HTML 页面, 获取 src 下每个文件下的 pageinfo.JSON 内容, 解析到 HtmlWebpackPlugin 中
- */
- const fs = require("fs");
- const HtmlWebpackPlugin = require("html-webpack-plugin");// 生成 HTML 文件
- const getFilePath = require("./getFilepath");
- let htmlArr = [];
- getFilePath("./src").map((item)=>{
- let infoJson ={},infoData={};
- try{
- // 读取 pageinfo.JSON 文件内容, 如果在页面目录下没有找到 pageinfo.JSON 捕获异常
- infoJson = fs.readFileSync(`src/${item}/pageinfo.json`,"utf-8");//
- infoData = JSON.parse(infoJson);
- }catch(err){
- infoData = {};
- }
- htmlArr.push(new HtmlWebpackPlugin({
- title:infoData.title ? infoData.title : "webpack,react 多页面架构",
- meta:{
- keywords: infoData.keywords ? infoData.keywords : "webpack,react,github",
- description:infoData.description ? infoData.description : "这是一个 webpack,react 多页面架构"
- },
- chunks:[`${item}/${item}`], // 引入的 JS
- template: "./src/template.html",
- filename : item == "index" ? "index.html" : `${item}/index.html`, //HTML 位置
- minify:{// 压缩 HTML
- collapseWhitespace: true,
- preserveLineBreaks: true
- },
- }));
- });
- module.exports = htmlArr;
wbpack 终极配置
- const path = require("path");
- const getEntry = require("./webpackConfig/getEntry"); // 入口配置
- const entry = getEntry("./src");
- const htmlArr =require("./webpackConfig/htmlConfig");// HTML 配置
- module.exports = (env, argv) => ({
- entry: entry
- output: {
- path: path.resolve(__dirname, 'dist'),
- filename: '[name].js'
- }
- ....// 其他配置
- devServer: {
- port: 3100,
- open: true,
- },
- plugins: [
- ...htmlArr
- ]
- })
这样一个自动化完整的多页面架构配置就完成了, 如果我们要新创建一个页面
在 src 下创建一个文件目录
在新创建的文件目录下添加 index.JS(必须, 因为是 webpack 打包入口文件)
在新创建文件夹下添加 pageinfo.JSON(非必须) 供 HTML 插件使用
NPM run dev 开发
完整代码参考项目 code https://github.com/leinov/webpack-react-multi-page
版本
版本 | 日期 | 分支 | 备注 |
---|---|---|---|
2.0 https://github.com/leinov/webpack-react-multi-page | 2018-11-08 | master | 优化 html 插件自动化 |
2018-10-07 | version1.0 | 第一版 |
来源: https://www.cnblogs.com/leinov/p/9932443.html