专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

冷启动4minampampgt2s的构建优化,怎么做到的?

  大家好,我是Echa哥。项目背景
  我们的系统(一个ToB的Web单页应用)经过多年的迭代,目前已经累积有大几十万行的业务代码,30路由模块,整体的代码量和复杂度还是比较高的。
  项目整体是基于VueTypeScirpt,而构建工具,由于最早项目是经由vuecli初始化而来,所以自然而然使用的是Webpack。
  我们知道,随着项目体量越来越大,我们在开发阶段将项目跑起来,也就是通过npmrunserve的单次冷启动时间,以及在项目发布时候的npmrunbuild的耗时都会越来越久。
  因此,打包构建优化也是伴随项目的成长需要持续不断去做的事情。在早期,项目体量比较小的时,构建优化的效果可能还不太明显,而随着项目体量的增大,构建耗时逐渐增加,如何尽可能的降低构建时间,则显得越来越重要:大项目通常是团队内多人协同开发,单次开发时的冷启动时间的降低,乘上人数及天数,经年累月节省下来的时间非常可观,能较大程度的提升开发效率、提升开发体验大项目的发布构建的效率提升,能更好地保证项目发布、回滚等一系列操作的准确性、及时性
  本文,就将详细介绍整个我们项目,在随着项目体量不断增大的过程中,对整体的打包构建效率的优化之路。瓶颈分析
  再更具体一点,我们的项目最初是基于vuecli4,当时其基于的是webpack4版本。如无特殊说明,下文的一些配置会基于webpack4展开。
  工欲善其事必先利其器,解决问题前需要分析问题,要优化构建速度,首先得分析出Webpack构建编译我们的项目过程中,耗时所在,侧重点分布。
  这里,我们使用的是SMP插件,统计各模块耗时数据。
  speedmeasurewebpackplugin是一款统计webpack打包时间的插件,不仅可以分析总的打包时间,还能分析各阶段loader的耗时,并且可以输出一个文件用于永久化存储数据。安装npminstallsavedevspeedmeasurewebpackplugin使用方式constSpeedMeasurePluginrequire(speedmeasurewebpackplugin);constsmpnewSpeedMeasurePlugin();config。plugins。push(smp());开发阶段构建耗时
  对于npmrunserve,也就是开发阶段而言,在没有任何缓存的前提下,单次冷启动整个项目的时间达到了惊人的4min。
  生产阶段构建耗时
  而对于npmrunbuild,也就是实际线上生产环境的构建,看看总体的耗时:
  因此,对于构建效率的优化可谓是势在必行。首先,我们需要明确,优化分为两个方向:基于开发阶段npmrunserve的优化
  在开发阶段,我们的核心目标是在保有项目所有功能的前提下,尽可能提高构建速度,保证开发时的效率,所以对于Live才需要的一些功能,譬如代码混淆压缩、图片压缩等功能是可以不开启的,并且在开发阶段,我们需要热更新。基于生产阶段npmrunbuild的优化
  而在生产打包阶段,尽管构建速度也非常重要,但是一些在开发时可有可无的功能必须加上,譬如代码压缩、图片压缩。因此,生产构建的目标是在于保证最终项目打包体积尽可能小,所需要的相关功能尽可能完善的前提下,同时保有较快的构建速度。
  两者的目的不尽相同,因此一些构建优化手段可能仅在其中一个环节有效。
  基于上述的一些分析,本文将从如下几个方面探讨对构建效率优化的探索:基于Webpack的一些常见传统优化方式分模块构建基于Vite的构建工具切换基于Esbuild插件的构建效率优化为什么这么慢?
  那么,为什么随着项目的增大,构建的效率变得越来越慢了呢?
  从上面两张截图不难看出,对于我们这样一个单页应用,构建过程中的大部分时间都消耗在编译JavaScript文件及CSS文件的各类Loader上。
  本文不会详细描述Webpack的构建原理,我们只需要大致知道,Webpack的构建流程,主要时间花费在递归遍历各个入口文件,并基于入口文件不断寻找依赖逐个编译再递归处理的过程,每次递归都需要经历StringASTString的流程,然后通过不同的loader处理一些字符串或者执行一些JavaScript脚本,由于NodeJS单线程的特性以及语言本身的效率限制,Webpack构建慢一直成为它饱受诟病的原因。
  因此,基于上述Webpack构建的流程及提到的一些问题,整体的优化方向就变成了:缓存多进程寻路优化抽离拆分构建工具替换基于Webpack的传统优化方式
  上面也说了,构建过程中的大部分时间都消耗在递归地去编译JavaScript及CSS的各类Loader上,并且会受限于NodeJS单线程的特性以及语言本身的效率限制。
  如果不替换掉Webpack本身,语言本身(NodeJS)的执行效率是没法优化的,只能在其他几个点做文章。
  因此在最早期,我们所做的都是一些比较常规的优化手段,这里简单介绍最为核心的几个:缓存多进程寻址优化缓存优化
  其实对于vuecli4而言,已经内置了一些缓存操作,譬如上图可见到loader的过程中,有使用cacheloader,所以我们并不需要再次添加到项目之中。cacheloader:在一些性能开销较大的loader之前添加cacheloader,以便将结果缓存到磁盘里
  那还有没有一些其他的缓存操作呢用上的呢?我们使用了一个HardSourceWebpackPlugin。HardSourceWebpackPluginHardSourceWebpackPlugin:HardSourceWebpackPlugin为模块提供中间缓存,缓存默认存放的路径是nodemodules。cachehardsource,配置了HardSourceWebpackPlugin之后,首次构建时间并没有太大的变化,但是第二次开始,构建时间将会大大的加快。
  首先安装依赖:npminstallhardsourcewebpackpluginD
  修改vue。config。js配置文件:constHardSourceWebpackPluginrequire(hardsourcewebpackplugin);module。exports{。。。configureWebpack:(config){。。。config。plugins。push(newHardSourceWebpackPlugin());},。。。}
  配置了HardSourceWebpackPlugin的首次构建时间,和预期的一样,并没有太大的变化,但是第二次构建从平均4min左右降到了平均20s左右,提升的幅度非常的夸张,当然,这个也因项目而异,但是整体而言,在不同项目中实测发现它都能比较大的提升开发时二次编译的效率。设置babelloader的cacheDirectory以及DLL
  另外,在缓存方面我们的尝试有:设置babelloader的cacheDirectoryDLL
  但是整体收效都不太大,可以简单讲讲。
  打开babelloader的cacheDirectory的配置,当有设置时,指定的目录将用来缓存loader的执行结果。之后的webpack构建,将会尝试读取缓存,来避免在每次执行时,可能产生的、高性能消耗的Babel重新编译过程。实际的操作步骤,你可以看看Webpackbabelloader。
  那么DLL又是什么呢?
  DLL文件为动态链接库,在一个动态链接库中可以包含给其他模块调用的函数和数据。
  为什么要用DLL?
  原因在于包含大量复用模块的动态链接库只需要编译一次,在之后的构建过程中被动态链接库包含的模块将不会在重新编译,而是直接使用动态链接库中的代码。
  由于动态链接库中大多数包含的是常用的第三方模块,例如Vue、React、Reactdom,只要不升级这些模块的版本,动态链接库就不用重新编译。
  DLL的配置非常繁琐,并且最终收效甚微,我们在过程中借助了autodllwebpackplugin,感兴趣的可以自行尝试。值得一提的是,Vuecli已经剔除了这个功能。多进程
  基于NodeJS单线程的特性,当有多个任务同时存在,它们也只能排队串行执行。
  而如今大多数CPU都是多核的,因此我们可以借助一些工具,充分释放CPU在多核并发方面的优势,利用多核优势,多进程同时处理任务。
  从上图中可以看到,VueCLi4中,其实已经内置了threadloader。threadloader:把threadloader放置在其它loader之前,那么放置在这个loader之后的loader就会在一个单独的worker池中运行。这样做的好处是把原本需要串行执行的任务并行执行。
  那么,除了threadloader,还有哪些可以考虑的方案呢?HappyPack
  HappyPack与threadloader类似。
  HappyPack可利用多进程对文件进行打包,将任务分解给多个子进程去并行执行,子进程处理完后,再把结果发送给主进程,达到并行打包的效、HappyPack并是所有的loader都支持,比如vueloader就不支持。
  可以通过LoaderCompatibilityList来查看支持的loaders。需要注意的是,创建子进程和主进程之间的通信是有开销的,当你的loader很慢的时候,可以加上happypack。否则,可能会编译的更慢。
  当然,由于HappyPack作者对JavaScript的兴趣逐步丢失,维护变少,webpack4及之后都更推荐使用threadloader。因此,这里没有实际结论给出。
  上一次HappyPack更新已经是3年前寻址优化
  对于寻址优化,总体而言提升并不是很大。
  它的核心即在于,合理设置loader的exclude和include属性。通过配置loader的exclude选项,告诉对应的loader可以忽略某个目录通过配置loader的include选项,告诉loader只需要处理指定的目录,loader处理的文件越少,执行速度就会更快
  这肯定是有用的优化手段,只是对于一些大型项目而言,这类优化对整体构建时间的优化不会特别明显。分模块构建
  在上述的一些常规优化完成后。整体效果仍旧不是特别明显,因此,我们开始思考一些其它方向。
  我们再来看看Webpack构建的整体流程:
  上图是大致的webpack构建流程,简单介绍一下:entryoption:读取webpack配置,调用newCompile(config)函数准备编译run:开始编译make:从入口开始分析依赖,对依赖模块进行buildbeforeresolve:对位置模块进行解析buildmodule:开始构建模块normalmoduleloader:生成AST树program:遍历AST树,遇到require语句收集依赖seal:build完成开始优化emit:输出dist目录
  随着项目体量地不断增大,耗时大头消耗在第7步,递归遍历AST,解析require,如此反复直到遍历完整个项目。
  而有意思的是,对于单次单个开发而言,极大概率只是基于这整个大项目的某一小个模块进行开发即可。
  所以,如果我们可以在收集依赖的时候,跳过我们本次不需要的模块,或者可以自行选择,只构建必要的模块,那么整体的构建时间就可以大大减少。
  这也就是我们要做的分模块构建。
  什么意思呢?举个栗子,假设我们的项目一共有6个大的路由模块A、B、C、D、E、F,当新需求只需要在A模块范围内进行优化新增,那么我们在开发阶段启动整个项目的时候,可以跳过B、C、D、E、F这5个模块,只构建A模块即可:
  假设原本每个模块的构建平均耗时3s,原本18s的整体冷启动构建耗时就能下降到3s。分模块构建打包的原理
  Webpack是静态编译打包的,Webpack在收集依赖时会去分析代码中的require(import会被bebel编译成require)语句,然后递归的去收集依赖进行打包构建。
  我们要做的,就是通过增加一些配置,简单改造下我们的现有代码,使得Webpack在初始化遍历整个路由模块收集依赖的时候,可以跳过我们不需要的模块。
  再说得详细点,假设我们的路由大致代码如下:importVuefromvue;importVueRouter,{Route}fromvuerouter;1。定义路由组件。这里简化下模型,实际项目中肯定是一个一个的大路由模块,从其他文件导入constmoduleA{template:AAAA}constmoduleB{template:BBBB}constmoduleC{template:CCCC}constmoduleD{template:DDDD}constmoduleE{template:EEEE}constmoduleF{template:FFFF}2。定义一些路由每个路由都需要映射到一个组件。我们后面再讨论嵌套路由。constroutesConfig〔{path:A,component:moduleA},{path:B,component:moduleB},{path:C,component:moduleC},{path:D,component:moduleD},{path:E,component:moduleE},{path:F,component:moduleF}〕constrouternewVueRouter({mode:history,routes:routesConfig,});让路由生效。。。constappVue。createApp({})app。use(router)
  我们要做的,就是每次启动项目时,可以通过一个前置命令行脚本,收集本次需要启动的模块,按需生成需要的routesConfig即可。
  我们尝试了:IgnorePlugin插件webpackvirtualmodules配合require。contextNormalModuleReplacementPlugin插件进行文件替换
  最终选择了使用NormalModuleReplacementPlugin插件进行文件替换的方式,原因在于它对整个项目的侵入性非常小,只需要添加前置脚本及修改Webpack配置,无需改变任何路由文件代码。总结而言,该方案的两点优势在于:无需改动上层代码通过生成临时路由文件的方式,替换原路由文件,对项目无任何影响使用NormalModuleReplacementPlugin生成新的路由配置文件
  利用NormalModuleReplacementPlugin插件,可以不修改原来的路由配置文件,在编译阶段根据配置生成一个新的路由配置文件然后去使用它,这样做的好处在于对整个源码没有侵入性。
  NormalModuleReplacementPlugin插件的作用在于,将目标源文件的内容替换为我们自己的内容。
  我们简单修改Webpack配置,如果当前是开发环境,利用该插件,将原本的config。ts文件,替换为另外一份,代码如下:vue。config。jsif(process。env。NODEENVdevelopment){config。plugins。push(newwebpack。NormalModuleReplacementPlugin(srcrouterconfig。ts,。。。。dev。routerConfig。ts))}
  上面的代码功能是将实际使用的config。ts替换为自定义配置的dev。routerConfig。ts文件,那么dev。routerConfig。ts文件的内容又是如何产生的呢,其实就是借助了inquirer与EJS模板引擎,通过一个交互式的命令行问答,选取需要的模块,基于选择的内容,动态的生成新的dev。routerConfig。ts代码,这里直接上代码。
  改造一下我们的启动脚本,在执行vuecliserviceserve前,先跑一段我们的前置脚本:{。。。scripts:{dev:vuecliserviceserve,dev:node。scriptdevserver。jsvuecliserviceserve,},。。。}
  而devserver。js所需要做的事,就是通过inquirer实现一个交互式命令,用户选择本次需要启动的模块列表,通过ejs生成一份新的dev。routerConfig。ts文件。devserver。jsconstejsrequire(ejs);constfsrequire(fs);constchildprocessrequire(childprocess);constinquirerrequire(inquirer);constpathrequire(path);constmoduleConfig〔moduleA,moduleB,moduleC,实际业务中的所有模块〕选中的模块constchooseModules〔home〕functiondeelRouteName(name){constindexname。search(〔AZ〕g);constpreRoutepath。resolve(dirname,。。srcroutermodules);if(!〔0,1〕。includes(index)){returnpreRoute(name。slice(0,index)name。slice(index))。toLowerCase();}returnpreRoutename。toLowerCase();;}functioninit(){letentryDirprocess。argv。slice(2);entryDir〔。。。newSet(entryDir)〕;if(entryDirentryDir。length0){for(constitemofentryDir){if(moduleConfig。includes(item)){chooseModules。push(item);}}console。log(output:,chooseModules);runDEV();}else{promptModule();}}constgetContenTemplateasync(){consthtmlawaitejs。renderFile(path。resolve(dirname,router。config。template。ejs),{chooseModules,deelRouteName},{async:true});fs。writeFileSync(path。resolve(dirname,。。dev。routerConfig。ts),html);};functionpromptModule(){inquirer。prompt({type:checkbox,name:modules,message:请选择启动的模块,点击上下键选择,按空格键确认(可以多选),回车运行。注意:直接敲击回车会全量编译,速度较慢。,pageSize:15,choices:moduleConfig。map((item){return{name:item,value:item,}})})。then((answers){if(answers。modules。length0){chooseModules。push(。。。moduleConfig)}else{chooseModules。push(。。。answers。modules)}runDEV();});}init();
  模板代码的简单示意:模板代码示意,router。config。template。ejsimport{RouteConfig}fromvuerouter;lt;chooseModules。forEach(function(item){importlt;itemfromlt;deelRouteName(item);lt;})letroutesConfig:ArrayRouteConfig〔〕;eslintdisableroutesConfig〔lt;chooseModules。forEach(function(item){lt;item,lt;})〕exportdefaultroutesConfig;
  devserver。js的核心在于启动一个inquirer交互命令行服务,让用户选择需要构建的模块,类似于这样:
  模板代码示意router。config。template。ejs是EJS模板文件,chooseModules是我们在终端输入时,获取到的用户选择的模块集合数组,根据这个列表,我们去生成新的routesConfig文件。
  这样,我们就实现了分模块构建,按需进行依赖收集。以我们的项目为例,我们的整个项目大概有20个不同的模块,几十万行代码:
  构建模块数耗时冷启动全量构建20个模块4。5MIN冷启动只构建1个模块18s有缓存状态下二次构建1个模块4。5s
  实际效果大致如下,无需启动所有模块,只启动我们选中的模块进行对应的开发即可:
  这样,如果单次开发只涉及固定的模块,单次项目冷启动的时间,可以从原本的4min下降到18s左右,而有缓存状态下二次构建1个模块,仅仅需要4。5s,属于一个比较大的提升。
  受限于Webpack所使用的语言的性能瓶颈,要追求更快的构建性能,我们不可避免的需要把目光放在其他构建工具上。这里,我们的目光聚焦在了Vite与esbuild上。使用Vite优化开发时构建
  Vite,一个基于浏览器原生ES模块的开发服务器。利用浏览器去解析imports,在服务器端按需编译返回,完全跳过了打包这个概念,服务器随起随用。同时不仅有Vue文件支持,还搞定了热更新,而且热更新的速度不会随着模块增多而变慢。
  当然,由于Vite本身特性的限制,目前只适用于在开发阶段替代Webpack。
  我们都知道Vite非常快,它主要快在什么地方?项目冷启动更快热更新更快
  那么是什么让它这么快?Webpack与Vite冷启动的区别
  我们先来看看Webpack与Vite的在构建上的区别。下图是Webpack的遍历递归收集依赖的过程:
  上文我们也讲了,Webpack启动时,从入口文件出发,调用所有配置的Loader对模块进行编译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理。
  这一过程是非常非常耗时的,再看看Vite:
  Vite通过在一开始将应用中的模块区分为依赖和源码两类,改进了开发服务器启动时间。它快的核心在于两点:使用Go语言的依赖预构建:Vite将会使用esbuild进行预构建依赖。esbuild使用Go编写,并且比以JavaScript编写的打包器预构建依赖快10100倍。依赖预构建主要做了什么呢?开发阶段中,Vite的开发服务器将所有代码视为原生ES模块。因此,Vite必须先将作为CommonJS或UMD发布的依赖项转换为ESMVite将有许多内部模块的ESM依赖关系转换为单个模块,以提高后续页面加载性能。如果不编译,每个依赖包里面都可能含有多个其他的依赖,每个引入的依赖都会又一个请求,请求多了耗时就多按需编译返回:Vite以原生ESM方式提供源码。这实际上是让浏览器接管了打包程序的部分工作:Vite只需要在浏览器请求源码时进行转换并按需提供源码。根据情景动态导入代码,即只在当前屏幕上实际使用时才会被处理。Webpack与Vite热更新的区别
  使用Vite的另外一个大的好处在于,它的热更新也是非常迅速的。
  我们首先来看看Webpack的热更新机制:
  一些名词解释:Webpackcomplier:Webpack的编译器,将Javascript编译成bundle(就是最终的输出文件)HMRServer:将热更新的文件输出给HMRRuntimeBunbleServer:提供文件在浏览器的访问,也就是我们平时能够正常通过localhost访问我们本地网站的原因HMRRuntime:开启了热更新的话,在打包阶段会被注入到浏览器中的bundle。js,这样bundle。js就可以跟服务器建立连接,通常是使用Websocket,当收到服务器的更新指令的时候,就去更新文件的变化bundle。js:构建输出的文件
  Webpack热更新的大致原理是,文件经过Webpackcomplier编译好后传输给HMRServer,HMRServer知道哪个资源(模块)发生了改变,并通知HMRRuntime有哪些变化,HMRRuntime就会更新我们的代码,这样浏览器就会更新并且不需要刷新。
  而Webpack热更新机制主要耗时点在于,Webpack的热更新会以当前修改的文件为入口重新build打包,所有涉及到的依赖也都会被重新加载一次。
  而Vite号称热更新的速度不会随着模块增多而变慢。它的主要优化点在哪呢?
  Vite实现热更新的方式与Webpack大同小异,也通过创建WebSocket建立浏览器与服务器建立通信,通过监听文件的改变向客户端发出消息,客户端对应不同的文件进行不同的操作的更新。
  Vite通过chokidar来监听文件系统的变更,只用对发生变更的模块重新加载,只需要精确的使相关模块与其临近的HMR边界连接失效即可,这样HMR更新速度就不会因为应用体积的增加而变慢而Webpack还要经历一次打包构建。所以HMR场景下,Vite表现也要好于Webpack。
  通过不同的消息触发一些事件。做到浏览器端的即时热模块更换(热更新)。通过不同事件,触发更细粒度的更新(目前只有Vue和JS,Vue文件又包含了template、script、style的改动),做到只更新必须的文件,而不是全量进行更新。在些事件分别是:connected:WebSocket连接成功vuereload:Vue组件重新加载(当修改了script里的内容时)vuererender:Vue组件重新渲染(当修改了template里的内容时)styleupdate:样式更新styleremove:样式移除jsupdate:js文件更新fullreload:fallback机制,网页重刷新
  本文不会在Vite原理上做太多深入,感兴趣的可以通过官方文档了解更多Vite官方文档为什么选Vite
  基于Vite的改造,相当于在开发阶段替换掉Webpack,下文主要讲讲我们在替换过程中遇到的一些问题。
  基于Vuecli4的Vue2项目改造,大致只需要:安装Vite配置index。html(Vite解析

硅谷银行倒闭,美国银行板块大跌,美国金融危机要来了吗?3月9日晚上,美国的银行板块出现暴跌,美国四大银行市值蒸发524亿美元,标普500银行指数暴跌近6。引发如此恐慌性抛售的导火索,是美国的硅谷银行出现流动性危机,在3月9日晚上,硅谷202311凯盛大蒜行情大蒜行情信息今日金乡产区库蒜行情微涨趋稳,交易量尚可,主流成交价格重心有不明显上移。上午,待售货源供给延续常态表现,卖家普遍随行或坚持售货,低价及大吨位货源有一定撑价表现,刚需买家西安迈向新经济时代北跨战略再造万亿级工业走廊拉大城市骨架,做大工业体系,扩大都市格局,当三大目标同时摆在西安面前时,应当如何破局?西安给出一个答案向北跨一步。这个被称为北跨的战略,是西安蓄势多年的城市战略,也是在万亿GDP城南阳未来10年发展省域副中心枢纽大城华源厨具助力南阳餐饮业发展。进入2023年,全国多地吹响了全力拼经济拼发展的冲锋号。作为河南省副中心城市,南阳市铆足干劲,全力推动现代化省域副中心城市建设。南阳的目标是打造绿色食品求职旺季,这些新坑要避开公开招聘凶宅试睡员,日薪2000元,工作内容包括在凶宅试睡并勘察有无异常等。近日,浙江杭州一公司开设岗位招聘凶宅试睡员,丰厚的报酬和轻松躺赚的工作内容引来不少关注。然而,有专业人士如今的马蓉,已经如此落魄了?终究为自己的贪得无厌付出了代价和王宝强离婚7年,马蓉估计不会想到,自己会以这样的形式再度成为热门话题。离开王宝强后的马蓉,日子并不好过,如今生活有些落魄。养了猫的马蓉,如今昂贵的猫粮也买不起了,想用一些便宜一点今年会出台延迟退休政策吗?总理我们正在认真研究今天上午,记者们提出了大家关心的今年会不会出台延迟退休政策问题。李强总理表示我们一定会认真研究,充分论证,在合适的时候稳妥推出。男人的终点是保安,女人的终点是保洁,这是很多人对于未快递小哥每天给自己送上百个包裹,咋回事?今天(11日)下午的委员通道上,全国政协委员曹鹏讲述了快递小哥檀世旺的故事。檀世旺在安徽石台县送快递,他每天要配送上百单寄给檀世旺的快递,这是怎么回事?01hr带着寄给自己的包裹快我向总书记话新愿创造城市美好生活将农民工们呼声带到人民大会堂编者按每年全国两会,习近平总书记都会同来自基层的代表委员面对面交流,听民声话心愿。每一份问候与嘱托,饱含关怀与期待。2023年全国两会,央广网推出特别策划我向总书记话新愿,讲述来自中科院专利产品微生物菌剂DX9菌株可耐受高盐环境微生物菌剂DX9的技术创始人是中国科学院微生物研究所农业室仲乃琴教授,她与技术团队依托中科院农业微生物先进技术工程实验室和基因组学国家实验室,通俗一点讲就是我国微生物界的国家队,我同济大学吉林大学华南理工大学考研复试线公布!3月10日晚,考研国家线已经公布,在国家线之后,大家最关心的无疑就是院校线了。北京大学清华大学浙江大学等高校最先公布了自己院校的复试线,现在同济大学吉林大学华南理工大学等985高校
裸车1520W,家用轿车,买哪款好?一般来说,家用轿车我们比较注重空间,在1520万的区间里,一些合资B级车是可以考虑的,B级车的空间优势不言而喻,另外合资的B级轿车不仅在空间上有优势,在动力配置上实力也很强。首先推河南人为什么要喝稀汤?在头条上,很多外乡人都很奇怪河南省为什么喝稀汤,也叫稀粥,他们百思不得其解,今天就让地地道道的河南人谈谈为什么河南人要喝稀汤吧!河南省一般是在早饭和晚饭喝稀粥,大家都知道,河南是农台湾人早餐都爱吃什么?一。西式早餐1。汉堡土司蛋饼现代人生活忙碌,为了方便快速,大多选择在早餐店吃早餐或直接買到学校公司。怎么说早餐也是一天活力的來源,最好能夠吃的像皇帝,这样子无论是上課或工作,一整天放开生育之后,以后是穷苦家庭孩子多,还是富裕家庭孩子多呢?应该是富家孩子多,老婆多,做官的孩子多,不超生了,合法了。现在的社会,早都已经不是孩子越多,劳动力越多,一只羊也是放,一群羊也是放的年代了,很多人不愿生孩子,就是因为自己能力不足,很多家庭的孩子在父母过世后慢慢就少来往或者不来往了,为什么?眼光短浅,只看眼前,鼠目寸光,缺乏亲情。父母在,家才在。父母亡就不互相来往,太可悲了。愿天下的儿女要团结互助,要充满爱,使团结的家风延传下去!父母在家就在,父母是维系大家庭的红线,黄瓜有什么营养,坚持吃一个月对身体有什么好处?您好,很高兴为您回答这个问题,我是赛普健身导师解鹏。黄瓜里面有一定的碳水化合物但是含量不算太高,蛋白质和脂肪含量都很低。在微量营养素方面富含钾,钙,镁等,黄瓜的含水量很高,可以给身孩子每次期末考试都是第一名,老师却只给她创三好不给三好,难道就因为孩子不善发言吗?我来谈谈这个问题。去年放寒假发奖状学校只给了10名三好学生的名额报上去。我和语文老师衡量再三,根据孩子们的综合表现选出了10名我们自认为相对来说品学兼优的孩子报上去了。其它学生发的去西安旅游,有哪些套路要注意?谢邀。首先欢迎你来西安旅游。其实,不管你去哪里旅游,都有可能被黑或者说被套路。只要你不抱着占便宜的心态,一般不会被吭的。但是,到西安旅游还是有些要注意的。先说最乱的地方,那就是火车从云南自驾去泰国,走昆曼高速,国内车和人需要办理哪些手续?这个问题我来回答你这个提问和回答是十多年前的,情况早就发生变化,老挝会晒横跨湄公河到泰国清孔2013年12月12日就建成大桥并通车,大桥通车自然就不用摆渡了。还有大桥通车后没多久就滴滴还能撑多久,还能回到以前吗?滴滴7部门联查完公布结果就是死期,现在快到国庆了,请全国的司机师傅们都不要接滴滴平台订单了,都退岀吧!滴滴公司绝对不会倒,我说说我的观点一,滴滴APP虽已下架,但是滴滴只要司机还在高二的数学怎么提高?说到这件事,我太有发言权了。我高中数理化一开始也是特别烂,在高二利用暑假到国庆的时间实现了质的飞跃。年代久远,这篇回答是半回忆的,但万变不离其宗,希望我的经历能对你有帮助。首先要看
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网