当前位置: 首页 > 后端技术 > Node.js

多页面架构(webpack+express)的前后端分离方案

时间:2023-04-03 23:33:13 Node.js

SPA(单页面架构)方案目前很流行,但是大部分网站还是选择多页面或者单页面+多页面混合架构。本文使用express和webpack,低成本实现了多页面架构、自动刷新、前后端分离等概念。一、项目gitreponode-pages-webpack-hotdevelopmentnpminstallnpminstallsupervisor-gnpmrunstart#开发环境,配置hotreloadnpmrunprod#生产环境npmrunbuild#编译前端生产环境DEMOFE目录:SERVER目录:为了不浪费大家的时间,阅读以下内容需要有express的基础知识,以及对node的简单了解和对webpack的中级了解,本文使用webpack2实现1.FE端配置.前端配置需要实现的功能点:多页面架构自动生成入口,通过html-webpack-plugin为每个页面生成模板,选择任意模板引擎需要实现布局模板功能(本文使用swig作为模板引擎)配置各种文件后缀的加载器,使用HotModuleReplacementPlugin实现自刷新1.1自动解析入口规定每个页面必须有一个与本页入口同名的js文件,目录深度可变,如下图,分解为两个entry:为了实现自动获取,使用glob获取所有.js文件,判断是否有同名的.html,如果有,则生成一个entry,如果这是一个开发环境,添加更多hotMiddlewareScript模块//获取所有js文件letfiles=glob.sync(config.src+'/**/*.js');让srcLength=config.src.length;让条目={};files.forEach(function(_file){letfile=path.parse(_file);lethtmlFile=path.resolve(file.dir,file.name+'.'+config.ext);//如果有同名模板文件,它是一个条目if(fs.existsSync(htmlFile)){letpathIndex=file.dir.indexOf(config.src);if(config.dev=='dev'){entries[config.staticRoot+file.dir.slice(srcLength)+'/'+file.name]=[path.resolve(_file),hotMiddlewareScript];}else{entries[config.staticRoot+file.dir.slice(srcLength)+'/'+file.name]=path.resolve(_file);}}});返回条目;1.2自动生成html-webpack-plugin模板生成一系列HtmlWebpackPlugin的要点如下:获取所有.html后,判断是否有对应的入口文件,有则创建HtmlWebpackPlugin如果页面为布局模板,则需要注入更多CommonsChunkPlugin生成的通用模块自动生成HtmlWebpackPlugin代码如下:lethtmls=[];//获取所有模板letfiles=glob.sync(config.src+'/**/*.'+config.ext);让srcLength=config.src.length;files.forEach(function(_file){letfile=path.parse(_file);letchunks=[];letchunkName=config.staticRoot+file.dir.slice(srcLength)+'/'+file.name;//如果有同名条目,创建一个html插件letc=entrys[chunkName];c&&chunks.push(块名);//布局将包含公共块if(file.name==config.serverLayoutName){chunks.push(config.staticRoot+'/common');}letplugin=newHtmlWebpackPlugin({filename:config.templateRoot+file.dir.slice(srcLength)+'/'+file.base,template:path.resolve(file.dir,file.base),chunks:chunks,注入:假});htmls.push(插件);});返回html;由于引入了templateextendssupport,需要设置inject=false,这样assets文件就不会被自动注入。写一个webpack插件,将页面的js资源和css资源注入:两个替换文案地方,比如页面模板:{%extends'../base/base.html'%}{%blocktitle%}MyPage{%endblock%}{%blockstyle%}{%endblock%}{%blockhead%}{%parent%}{%endblock%}{%blockcontent%}

这只是一个主页!!!

linkpage2{%endblock%}{%blockscript%}{%endblock%}被编译并替换为:{%extends'../base/base.html'%}{%blocktitle%}MyPage{%endblock%}{%blockstyle%}{%endblock%}{%blockhead%}{%parent%}{%endblock%}{%blockcontent%}

这只是一个主页!!!

linkpage2{%endblock%}{%blockscript%}{%endblock%}1.3各种loader配置,提取页面cssdev环境下配置了webpack-hot-middleware,所以不能提取css,否则热更新样式相关的loader配置如下如下:varextractInstance=newExtractTextPlugin('[name].css');if(config.env=='dev'){varstylusLoader=[{loader:'style-loader'},{loader:'css-loader'},{loader:'stylus-loader'}];varcssLoader=[{loader:'style-loader'},{loader:'css-loader'}];}else{varstylusLoader=extractInstance.extract(['css-loader','stylus-loader']);varcssLoader=extractInstance.extract(['css-loader']);}并将所有加载器放在同一个文件中进行维护:node_modules/,使用:cssLoader},{test:/\.html$/,使用:{loader:'html-loader',options:{minimize:false}}},............]1.4路径配置统一控制生成模板和静态文件输出目录,方便与各种后端架构结合constport=process.env.PORT||8080;constenv=process.env.NODE_ENV||'dev';constCONFIG_BUILD={env:env,ext:'html',//模板extsrc:path.resolve(__dirname,'../src'),//源代码路径path:env=='dev'?'/':path.resolve(__dirname,'../dist'),//基本输出路径templateRoot:'templates',//模板输出路径staticRoot:'static',//静态输出路径serverLayoutName:'base',//swig布局名称,只有一个文件publicPath:env=='dev'?('http://localhost:'+port+'/'):'/'}2.配置服务端,在服务端搭建express服务。实现的功能如下:使用webpack-dev-middleware进行webpack编译,使用webpack-hot-middleware实现热重载使用supervisor服务监听节点文件变化自动重启render模板将内存中的文件写入硬盘diskforrendering2.1webpackaccessexpress生成webpack编译器varwebpack=require('webpack'),webpackDevConfig=require(path.resolve(config.root,'./fe/webpack.config.js'));varcompiler=webpack(webpackDevConfig);使用编译器作为快速中间件//附加到编译器和服务器app.use(webpackDevMiddleware(compiler,{//公共路径应该与webpack配置相同publicPath:webpackDevConfig.output.publicPath,noInfo:false,stats:{colors:真的}}));其中publicPath指定assets请求的根路径,这里的配置是:http://localhost:8080/2.2hotreload解决方案2.2.1js,css修改自刷新js和css的自刷新是通过配置webpack-hot-middleware实现的(fe也需要相应配置)//serverconstwebpackHotMiddleware=require('webpack-hot-中间件');app.use(webpackHotMiddleware(编译器));//fewebpackPlugins.push(newwebpack.HotModuleReplacementPlugin());2.2.2节点修改自刷新节点文件修改通过配置supervisor服务实现自动刷新安装服务:npminstallsupervisor-g配置启动参数://package.json"scripts":{"start":"cross-envNODE_ENV=devsupervisor-wserver-efeserver/server.js"}supervisor监听server文件夹下的所有变化,变化后重启express服务如果要自动刷新浏览器,需要在布局模板中添加如下代码:{%ifenv=='dev'%}{%endif%}2.3rendertemplate使用webpack作为express中间件时,所有生成的文件都保存在内存中,当然也包括html-webpack-plugin生成的模板文件。但是express的render函数只能指定一个存在于文件系统中的模板,即在dev环境中渲染模板之前,需要先从内存中获取并存储到文件系统中。module.exports=(res,template)=>{if(config.env=='dev'){letfilename=compiler.outputPath+template;//从compiler.outputFileSystem.readFile(filename,function(err,result){letfileInfo=path.parse(path.join(config.templateRoot,filename));mkdirp(fileInfo.dir,()=>{fs.writeFileSync(path.join(config.templateRoot,filename),result);res.render(template);});});}else{res.render(模板);}}布局模板存储需要一个中间件:layoutTemplate;compiler.outputFileSystem.readFile(filename,function(err,result){letfileInfoLayout=path.parse(layoutPath);mkdirp(fileInfoLayout.dir,()=>{fs.writeFileSync(layoutPath,result);next();});});});其余以express为主,请参考文档中的2.4Proxy后端接口在dev环境中,使用http-proxy-middleware代理后端接口://setproxyapp.use('/api',proxy({target:config.proxy,changeOrigin:true}));所有/api请求都会被代理到config.proxy配置的ip端口。正式环境下,直接配置nginx进行转发。补充本文只是简单的搭建了一个前后端分离的框架,但是还有很多不完善的地方。真正的线上应用还需要考虑nodejs的运维成本、日志、监控等。