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 如何设置?
描述 和 关键词 如何设置?
我们现在来解决这些问题!!!!!!!!!!
设置 entry 入口文件
我们在 config 文件夹中 新建 entry.js ,以后我们新建页面,只需要在这里添加即可
path路径 会指向到 app->component 目录下
letentry = [
{
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以外的所有文件。
// *.+(jscss):匹配项目根目录下,所有后缀名为js或css的文件。
//流 stream 管道 pipe 管道
//如果想在读取流和写入流的时候做完全的控制,可以使用数据事件。但对于单纯的文件复制来说读取流和写入流可以通过管道来传输数据。
/*
* 复制目录中的所有文件包括子目录
* @src param{ String } 需要复制的目录 例 images 或者 ./images/
* @dst param{ String } 复制到指定的目录 例 images images/
*/
constfs =require("fs");
constpath =require("path");
//获取当前目录绝对路径,这里resolve()不传入参数
constfilePath = path.resolve();
constcopy=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系统是”\“
varurl = 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)throwerr;
//是文件
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;
}
};
functionexists(url,dest,callback){
fs.exists(dest,function(exists){
if(exists){
callback && callback(url,dest);
}else{
//第二个参数目录权限 ,默认0777(读写权限)
fs.mkdir(dest,0777,function(err){
if(err)throwerr;
callback && callback(url,dest);
});
}
});
}
module.exports=copy;
建立deleteFile.js
constfs =require("fs");
constdeleteFolderRecursive=function(path) {
if(fs.existsSync(path)) {
fs.readdirSync(path).forEach(function(file,index) {
letcurPath = path +"/"+ file;
if(fs.lstatSync(curPath).isDirectory()) {// recurse
deleteFolderRecursive(curPath);
}else{// delete file
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(path);
}
};
module.exports=deleteFolderRecursive;
建立 imgDel.js
letfs =require('fs');
letjoin =require('path').join;
/**
*
*@paramstartPath 起始目录文件夹路径
*@returns
*/
functionfindSync(startPath) {
letresult = [];
functionfinder(path) {
letfiles = fs.readdirSync(path);
files.forEach((val,index) => {
letfPath = join(path,val);
letstats = fs.statSync(fPath);
if(stats.isDirectory())finder(fPath);
if(val.indexOf('png') !==-1val.indexOf('gif') !==-1val.indexOf('jpg') !==-1){
if(stats.isFile()) result.push(val.substring(,val.length-12));
}
});
}
finder(startPath);
returnresult;
}
letfileNames =findSync('pc/resource/');
console.log(fileNames);
建立 nodeCommon.js
constdeleteFile=require("./deleteFile");
constcopyFile=require("./copyFile");
module.exports= {
deleteFile,
copyFile
};
建完后目录结构如下
3.新建entryBuild.js
constfs =require("fs");
constpath =require("path");
constentry =require('./entry');
constnodeCommon=require('../common/nodeCommon');
constentryBuildPath = path.resolve(__dirname,'../../entryBuild');
nodeCommon.deleteFile(entryBuildPath);
fs.mkdirSync(entryBuildPath);
constentryContent= (data) => {
letcont =``;
return`
import React from 'react';
import ReactDOM from 'react-dom';
import Index from '../app/component/$';
ReactDOM.render($,document.getElementById('app'));
`
};
/*生成webpack entry 入口文件*/
entry.map((data) => {
fs.writeFile(entryBuildPath +'/'+ data.name+'.js',entryContent(data),'utf8',function(err) {
if(err) {
returnconsole.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
放在根目录下
6.建立几个公用webpack js文件
lettitleFun=function(chunkName,title){
lettitleDef ='XXX网站';
if(chunkName.indexOf('index') !==-1){
returntitleDef;
}else{
returntitle +'_'+ titleDef;
}
};
module.exports= {
titleFun:titleFun
};
添加依赖
npmi-D copy-webpack-plugin clean-webpack-plugin
constpath =require("path");
constCopyWebpackPlugin =require('copy-webpack-plugin');
constCleanWebpackPlugin =require('clean-webpack-plugin');
functioncleanFun(arr) {
return(newCleanWebpackPlugin(arr,{root: path.resolve(__dirname,'../../'),verbose:true,dry:false}))
}
letcopyObj = [
/*,
,
,
,*/
];
letcopyArr = [];
copyObj.map((data) => {
copyArr.push(
newCopyWebpackPlugin([{from: data.from,to: data.to,ignore: ['.*']}])
)
});
module.exports= {
devDirectory:'build',/*开发目录*/
proDirectory:'pc',/*发布目录*/
resource:'resource',/*静态资源*/
resourcePrefix:'/static/pc/',/*线上静态资源前缀*/
cleanFun:cleanFun,
copyArr: copyArr,
copyObj: copyObj
};
constfs =require("fs");
constnodeCommon=require("../common/nodeCommon");
constwebpackFile=require("./webpack.file.conf");
constentryBuild =require('../entry/entry');
constwebpackComConf =require('./webpack.com.conf');
/*删除构建目录*/
nodeCommon.deleteFile(webpackFile.devDirectory);
/*创建构建目录*/
fs.mkdirSync(webpackFile.devDirectory);
webpackFile.copyObj.map((data) => {
letto =webpackFile.devDirectory+ data.to.substring(1,data.to.length);
if(data.to!=='./') {
fs.mkdirSync(to);
}
nodeCommon.copyFile(data.from,to);
});
/*生成HTML*/
lethtmlCont = fs.readFileSync("index.html","utf-8");
letscriptInsert =`
`;
htmlCont = htmlCont.replace('',scriptInsert +'');
entryBuild.map((data) => {
fs.writeFile(webpackFile.devDirectory+'/'+ data.name+'.html',
htmlCont.replace('js/key.js','js/'+ data.name+'.js').replace('',webpackComConf.titleFun(data.name,data.title)),
'utf8',
function(err) {
if(err) {
returnconsole.log(err);
}
});
});
8.修改package.json
"devBuildHtml":"node config/webpack/webpack.devBuildHtml.conf.js",
我们删除 根目录下的 build 文件夹,然后执行
npm run devBuildHtml
看下是否自动生成了 build 文件夹 和 index.html shop.html 文件
constentryBuild =require('../entry/entry');
letentry = {};
entryBuild.map((data) => {
entry[data.name] = ['./entryBuild/'+ data.name+'.js',data.title];
});
module.exports= entry;
constentry =require("./webpack.entry.conf");
constjson =require('../../package.json');//引进package.json
constnewEntry = {};
for(letnameinentry) {
newEntry[name] = entry[name][]
}
newEntry.vendor= Object.keys(json.dependencies);//把 package.json dependencies字段的值放进 vendor中
letconfig = {
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,我只是预留了这个功能)
然后 我们只需要
有新页面的时候执行
npmrundevNew
再执行
npmrundev
愉快的开发吧~~~~~~~~~~
本文完
禁止擅自转载,如需转载请在公众号中留言联系我们!
感谢童鞋们支持!
欢迎童鞋们留言!
领取专属 10元无门槛券
私享最新 技术干货