专栏首页前端人人React多页面应用4(webpack自动化生成多入口页面)

React多页面应用4(webpack自动化生成多入口页面)

本教程总共7篇,每日更新一篇,请关注我们!你可以进入历史消息查看以往文章,也敬请期待我们的新文章!

1.React多页面应用1(webpack开发环境搭建,包括Babel、热更新等) ----2017.12.28

2.React多页面应用2(处理CSS及图片,引入postCSS及图片处理等)----2017.12.29

3.React多页面应用3(webpack性能提升,包括打包性能、提取公共包等)----2017.12.30

4.React多页面应用4(webpack自动化生成多入口页面)----2017.12.31

5.React多页面应用5(webpack生产环境配置,包括压缩js代码,图片转码等)----2018.01.01

6.React多页面应用6(gulp自动化发布到多个环境,生成版本号,打包成zip等)----2018.01.02

7.React多页面应用7(引入eslint代码检查)----2018.01.03

开发环境:Windows 8,node v8.9.1,npm 5.5.1,WebStorm 2017.2.2

在之前课程中,我们发现,有很多重复劳动

如:

我们需要手动新建webpack入口文件

再 entryBuild 文件夹中新建,每个页面的js文件

index.js

shop.js

这两个文件 几乎是一样的

然后还需要在 build 文件夹中建立

两个对应的 html文件

index.html

shop.html

这两个文件几乎也是一样的

顺便还有一个问题就是

title 如何设置?

描述 和 关键词 如何设置?

我们现在来解决这些问题!!!!!!!!!!

  1. 设置 entry 入口文件 我们在 config 文件夹中 新建 entry.js ,以后我们新建页面,只需要在这里添加即可 path路径 会指向到 app->component 目录下
let entry = [
    {
        name: 'index',
        path: 'index/Index.jsx',
        title: '首页',
        keywords: '首页,xxx',
        description: '这是我们的首页'
    },
    {
        name: 'shop',
        path: 'shop/Index.jsx',
        title: '商城',
        keywords: '商城,xxx',
        description: '这是我们的商城'
    }
];
module.exports = entry;

2.接下来 我们要实现 自动化 生成 , webpack 的入口文件js,和html文件

在这之前我们需要写几个公共方法!

在config下,新建common

建立copyFile.js

// js/app.js:指定确切的文件名。
// js/*.js:某个目录所有后缀名为js的文件。
// js/**/*.js:某个目录及其所有子目录中的所有后缀名为js的文件。
// !js/app.js:除了js/app.js以外的所有文件。
// *.+(js|css):匹配项目根目录下,所有后缀名为js或css的文件。

//流 stream   管道 pipe 管道
//如果想在读取流和写入流的时候做完全的控制,可以使用数据事件。但对于单纯的文件复制来说读取流和写入流可以通过管道来传输数据。
/*
 * 复制目录中的所有文件包括子目录
 * @src param{ String } 需要复制的目录   例 images 或者 ./images/
 * @dst param{ String } 复制到指定的目录    例 images images/
 */
const fs = require("fs");
const path = require("path");
//获取当前目录绝对路径,这里resolve()不传入参数
const filePath = path.resolve();

const copy = function(src,dst){

    //判断文件需要时间,则必须同步
    if(fs.existsSync(src)){
        fs.readdir(src,function(err,files){
            if(err){console.log(err);return;}
            files.forEach(function(filename){

                //url+"/"+filename不能用/直接连接,Unix系统是”/“,Windows系统是”\“
                var url = path.join(src,filename),
                    dest = path.join(dst,filename);
                console.log(url);
                console.log(dest);
                fs.stat(path.join(src,filename),function(err, stats){
                    if (err) throw err;

                    //是文件
                    if(stats.isFile()){

                        //创建读取流
                        readable = fs.createReadStream(url);
                        //创建写入流
                        writable = fs.createWriteStream(dest,{ encoding: "utf8" });
                        // 通过管道来传输流
                        readable.pipe(writable);

                        //如果是目录
                    }else if(stats.isDirectory()){
                        exists( url, dest, copy );
                    }
                });
            });
        });
    }else{
        console.log("给定的目录不存,读取不到文件");
        return;
    }
};

function exists(url,dest,callback){
    fs.exists(dest,function(exists){
        if(exists){
            callback && callback(url,dest);
        }else{
            //第二个参数目录权限 ,默认0777(读写权限)
            fs.mkdir(dest,0777,function(err){
                if (err) throw err;
                callback && callback(url,dest);
            });
        }
    });
}
module.exports = copy;

建立deleteFile.js

const fs = require("fs");
const deleteFolderRecursive = function (path) {
    if (fs.existsSync(path)) {
        fs.readdirSync(path).forEach(function (file, index) {
            let curPath = path + "/" + file;
            if (fs.lstatSync(curPath).isDirectory()) { // recurse
                deleteFolderRecursive(curPath);
            } else { // delete file
                fs.unlinkSync(curPath);
            }
        });
        fs.rmdirSync(path);
    }
};

module.exports = deleteFolderRecursive;

建立 imgDel.js

let fs = require('fs');
let join = require('path').join;

/**
 *
 * @param startPath  起始目录文件夹路径
 * @returns {Array}
 */
function findSync(startPath) {
    let result = [];

    function finder(path) {
        let files = fs.readdirSync(path);
        files.forEach((val, index) => {
            let fPath = join(path, val);
            let stats = fs.statSync(fPath);
            if (stats.isDirectory()) finder(fPath);
            if(val.indexOf('png') !==-1 ||val.indexOf('gif') !==-1 || val.indexOf('jpg') !==-1){
                if (stats.isFile()) result.push(val.substring(0,val.length - 12));
            }
        });

    }

    finder(startPath);
    return result;
}

let fileNames = findSync('pc/resource/');
console.log(fileNames);

建立 nodeCommon.js

const deleteFile = require("./deleteFile");
const copyFile = require("./copyFile");
module.exports = {
    deleteFile,
    copyFile
};

建完后目录结构如下

3.新建entryBuild.js

const fs = require("fs");
const path = require("path");
const entry = require('./entry');
const nodeCommon = require('../common/nodeCommon');

const entryBuildPath = path.resolve(__dirname, '../../entryBuild');
nodeCommon.deleteFile(entryBuildPath);
fs.mkdirSync(entryBuildPath);

const entryContent = (data) => {
    let cont = `<Index />`;
    return `
import React from 'react';
import ReactDOM from 'react-dom';
import Index from '../app/component/${data.path}';
ReactDOM.render(${cont},document.getElementById('app'));
    `
};
/*生成webpack entry 入口文件*/
entry.map((data) => {
    fs.writeFile(entryBuildPath + '/' + data.name + '.js', entryContent(data), 'utf8', function (err) {
        if (err) {
            return console.log(err);
        }
    });
});

4.修改 package.json

"entry": "node config/entry/entryBuild.js",

我们现在 删除 entryBuild 文件夹

然后 执行 npm run entry

看下 是不是 创建了 entryBuild 文件夹 及 index.js shop.js

执行 npm run dev

一切正常

5.接下来我们自动化生成 html文件

我们需要建立一个模版 比如叫 index.html

放在根目录下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta content="telephone=no" name="format-detection">
    <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="app"></div>
</body>
</html>

6.建立几个公用webpack js文件

webpack.com.conf.js

let titleFun = function(chunkName,title){
    let titleDef = 'XXX网站';
    if(chunkName.indexOf('index') !==-1){
        return titleDef;
    }else{
        return title + '_' + titleDef;
    }
};
module.exports = {
    titleFun:titleFun
};

添加依赖

npm i -D copy-webpack-plugin clean-webpack-plugin

修改 webpack.file.conf.js 文件

const path = require("path");
const CopyWebpackPlugin = require('copy-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

function cleanFun(arr) {
    return (new CleanWebpackPlugin(arr, {root: path.resolve(__dirname, '../../'), verbose: true, dry: false}))
}

let copyObj = [
    /*{from: './app/public/plugin', to: './plugin'},
    {from: './app/public/versionTips', to: './versionTips'},
    {from: './app/public/file', to: './resource'},
    {from: './app/public/img/favicon.ico', to: './'},*/
];

let copyArr = [];
copyObj.map((data) => {
    copyArr.push(
        new CopyWebpackPlugin([{from: data.from, to: data.to, ignore: ['.*']}])
    )
});


module.exports = {
    devDirectory: 'build', /*开发目录*/
    proDirectory: 'pc', /*发布目录*/
    resource: 'resource', /*静态资源*/
    resourcePrefix: '/static/pc/', /*线上静态资源前缀*/
    cleanFun: cleanFun,
    copyArr: copyArr,
    copyObj: copyObj
};

7.新建 webpack.devBuildHtml.conf.js

const fs = require("fs");
const nodeCommon = require("../common/nodeCommon");
const webpackFile = require("./webpack.file.conf");
const entryBuild = require('../entry/entry');
const webpackComConf = require('./webpack.com.conf');
/*删除构建目录*/
nodeCommon.deleteFile(webpackFile.devDirectory);
/*创建构建目录*/
fs.mkdirSync(webpackFile.devDirectory);
webpackFile.copyObj.map((data) => {
    let to = webpackFile.devDirectory + data.to.substring(1, data.to.length);
    if (data.to !== './') {
        fs.mkdirSync(to);
    }
    nodeCommon.copyFile(data.from, to);
});
/*生成HTML*/
let htmlCont = fs.readFileSync("index.html", "utf-8");
let scriptInsert = `
<script type=text/javascript src=js/manifest.js></script>
<script type=text/javascript src=js/vendor.js></script>
<script type=text/javascript src=js/common.js></script>
<script type=text/javascript src=js/key.js></script>
`;
htmlCont = htmlCont.replace('</body>', scriptInsert + '</body>');
entryBuild.map((data) => {
    fs.writeFile(webpackFile.devDirectory + '/' + data.name + '.html',
        htmlCont.replace('js/key.js', 'js/' + data.name + '.js').replace('<%= htmlWebpackPlugin.options.title %>', webpackComConf.titleFun(data.name,data.title)),
        'utf8',
        function (err) {
            if (err) {
                return console.log(err);
            }
        });
});

8.修改package.json

"devBuildHtml": "node config/webpack/webpack.devBuildHtml.conf.js",

我们删除 根目录下的 build 文件夹,然后执行

npm run devBuildHtml

看下是否自动生成了 build 文件夹 和 index.html shop.html 文件

9.添加 webpack.entry.conf.js

const entryBuild = require('../entry/entry');
let entry = {};
entryBuild.map((data) => {
    entry[data.name] = ['./entryBuild/' + data.name + '.js', data.title];
});
module.exports = entry;

10.改造webpack.base.conf.js 统一入口文件

const entry = require("./webpack.entry.conf");
const json = require('../../package.json');//引进package.json
const newEntry = {};
for (let name in entry) {
    newEntry[name] = entry[name][0]
}
newEntry.vendor = Object.keys(json.dependencies); //把 package.json dependencies字段的值放进 vendor中
let config = {
    entry: newEntry,
    resolve: {
        extensions: [".js", ".json", ".jsx", ".css", ".pcss"],
    }
};
module.exports = config;

11.运行

npm run dev

一切OK

12.再往前走一步

修改 package.json

"devNew": "npm run entry && npm run devBuildHtml",

以后我们再有新页面,只需要在 config\entry\entry.js中添加就可以了

(目前 关键词,描述, 我们有去实现,也好实现,只是我们现在不太关注SEO,我只是预留了这个功能)

然后 我们只需要

有新页面的时候执行

npm run devNew

再执行

npm run dev

愉快的开发吧~~~~~~~~~~

本文分享自微信公众号 - 前端人人(frontend_everyone),作者:思铭

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-12-31

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • React多页面应用3(webpack性能提升,包括打包性能、提取公共包等)

    本教程总共7篇,每日更新一篇,请关注我们!你可以进入历史消息查看以往文章,也敬请期待我们的新文章! 1.React多页面应用1(webpack开发环境搭建,包...

    前端人人
  • React多页面应用6(gulp自动化发布到多个环境、生成版本号、压缩成zip等)

    本教程总共7篇,每日更新一篇,请关注我们!你可以进入历史消息查看以往文章,也敬请期待我们的新文章! 1.React多页面应用1(webpack开发环境搭建,包括...

    前端人人
  • React多页面应用2(处理CSS及图片,引入postCSS,及图片处理等)

    本教程总共7篇,每日更新一篇,请关注我们!你可以进入历史消息查看以往文章,也敬请期待我们的新文章! 1.React多页面应用1(webpack开发环境搭建,包...

    前端人人
  • 自动驾驶落地,究竟被什么绑住了脚?

    自动驾驶汽车的行驶范围将不再局限于测试跑道或是平静的郊区街道,它们出现在美国的纽约、旧金山以及匹兹堡等地,参与到真实世界的交通中去,也进驻欧洲、韩国、新加坡和日...

    企鹅号小编
  • 【机器学习入门】决策树的原理

    决策树(Decision Tree) 是一种数据结构,可以用来分类和回归,决策树是数据结构,但构建决策树有一系列的算法,决策树的核心之一就是利用算法构建最佳的决...

    Frank909
  • mac下导出chrome插件及安装

    3.命令行进入文件夹下想要打包的版本的目录内,输入pwd显示路径,然后复制

    薛定喵君
  • Meteor 1.4正式发布 - 更新了 Node 和 MongoDB 版本以及更多

    时见疏星
  • Spring Cloud Gateway 原生支持接口限流该怎么玩

    基于Spring Cloud、oAuth2.0开发基于Vue前后分离的开发平台,支持账号、短信、SSO等多种登录,提供配套视频开发教程。

    冷冷
  • Spring Cloud Gateway 原生的接口限流该怎么玩

    基于Spring Cloud、oAuth2.0开发基于Vue前后分离的开发平台,支持账号、短信、SSO等多种登录,提供配套视频开发教程。

    冷冷
  • Jupyter Notebook 扩展安装管理

    Notebook扩展是可以轻松添加到Jupyter笔记本中的插件。安装它们的最佳方法是使用Jupyter NbExtensions配置程序。它将添加一个选项卡以...

    spark

扫码关注云+社区

领取腾讯云代金券