解决webpack多页面内存溢出的方法示例


Posted in Javascript onOctober 08, 2019

因为自己的项目是基于vue-cli3进行开发,所以这里只讨论这种情况下的解决办法

在进行多页面开发的时候,项目刚开始阶段,因为文件较少,所以代码编译速度还行,但是随着项目逐渐增大,webpack编译的速度越来越慢,并且经常出现内存溢出的情况。

下面就是几种尝试的方法,加快编译的速度

增加Node运行内存

在Node中通过JavaScript使用内存时只能使用部分内存(64位系统下约为1.4 GB,32位系统下约为0.7 GB)。所以不管电脑实际的运行内存是多少,Node在运行代码编译的时候,使用内存大小不会发生变化。这样就可能导致因为原有的内存不够,导致内存溢出。所以可以增加Node的运行内存,下面是两种方法

更改cmd

在node_modules/.bin/vue-cli-server.cmd把下面代码复制上去

@IF EXIST "%~dp0\node.exe" (
 "%~dp0\node.exe" --max_old_space_size=4096 "%~dp0\..\@vue\cli-service\bin\vue-cli-service.js" %*
) ELSE (
 @SETLOCAL
 @SET PATHEXT=%PATHEXT:;.JS;=;%
 node --max_old_space_size=4096 "%~dp0\..\@vue\cli-service\bin\vue-cli-service.js" %*
)

更改package.json

把启动Node服务的更改下:

node --max_old_space_size=4096 node_modules/@vue/cli-service/bin/vue-cli-service.js serve

本质上没啥区别,都是通过强行增加Node的运行内存,来解决内存溢出的问题。但是这种方法不治本,虽然不会造成内存溢出,但是编译速度还是挺慢的,编译完成还是需要等很久。

配置需要编译的文件

这种就是按需配置需要编译的文件,为什么出现内存溢出,本质上还是因为需要编译的文件太多了,那我们就可以减少需要编译的页面就可以解决这个问题。

首先所有的页面配置都是放在page.config.js,如果我们需要对某些特定页面进行配置,就需要过滤所有的页面,获取需要编译的页面,下面是编译文件的写法

const path = require('path');
const fs = require('fs');
const pages = require('../pages.config');

const params = JSON.parse(process.env.npm_config_argv).original;
const buildPath = params[params.length - 1].match(/[a-zA-Z0-9]+/)[0] || '';

let buildConfig = {
 pages: [],
};


if (!/(test|online|serve)/gi.test(buildPath)) {
 const configJsPath = path.resolve(__dirname, `${buildPath}.js`);

 // 如果该路径存在
 if (fs.existsSync(configJsPath)) {
  // eslint-disable-next-line import/no-dynamic-require
  buildConfig = require(configJsPath);
 } else if (pages[buildPath]) {
  buildConfig.pages = buildPath.split(',');
 } else {
  throw new Error('该路径不存在');
 }
} else {
 buildConfig = require('./default');
}
module.exports = buildConfig.pages;

大多数情况下,一个产品都是由多个业务线构成,每次可能需要更改的就是某一条业务线,就完全可以单独创建一个这条业务线的配置文件,然后再这个文件写入你需要编译的页面名称,就可以单独编译这个页面,或者说在调用通过传入的字符串来编译那些页面

使用webbpack-dev-serve钩子进行单独编译

在webpack进行热更新的时候,实际上是使用了webpack-dev-server这个的服务,然后是否有钩子能够给我们提供,如果我们访问哪个页面他就编译那个页面的代码。幸运的是找到,在devServer中存在这么一个钩子函数before, 那就可以在vue.config.js中修改

const compiledPages = [];
before(app) {
   app.get('*.html', (req, res, next) => {
    const result = req.url.match(/[^/]+?(?=\.)/);
    const pageName = result && result[0];
    const pagesName = Object.keys(multiPageConfig);

    if (pageName) {
     if (pagesName.includes(pageName)) {
      if (!compiledPages.includes(pageName)) {
       const page = multiPageConfig[pageName];
       fs.writeFileSync(`dev-entries/${pageName}.js`, `import '../${page.tempEntry}'; // eslint-disable-line`);
       compiledPages.push(pageName);
      }
     } else {
      // 没这个入口
      res.writeHead(200, { 'content-type': 'text/html; charset=utf-8' });
      res.end('<p style="font-size: 50px;">不存在的入口</p>');
     }
    }
    next();
   });
  },

multPageConfig是多页面的配置,在开发环境中,做了一下修改,配置如下:

{
  pageName: {
    entry: entryPath,
    chunks: [array]
  }
}
const fs = require('fs');
const util = require('util');

const outputFile = util.promisify(fs.writeFile);
async function main() {
 const tasks = [];
 if (!fs.lstatSync('dev-entries').isDirectory()) {
  fs.mkdirSync('dev-entries');
 }
 Object.keys(pages).forEach((key) => {
  const entry = `dev-entries/${key}.js`;
  pages[key].tempEntry = pages[key].entry; // 暂存真正的入口文件地址
  pages[key].entry = entry;
  tasks.push(outputFile(entry, ''));
 });
 await Promise.all(tasks);
}

if (process.env.NODE_ENV === 'development') {
 main();
}

module.exports = pages;

在上面文件中,我们首先需要更改多页面的配置,创建一个目录,包含所有的页面的js文件,但是需要注意的是这些文件都是空的文件,什么都没有,然后在vue.config.js中多页面的配置为

pages: multiPageConfig, // 配置多页应用

因为所有的页面js已经被置为空了,所以编译的速度非常快。然后再访问页面的时候,webpack已经拦截访问的页面,也就是需要更改的页面,这时候就手动往dev-entries目录下写入需要编译的文件,从而实现了访问某个页面就编译哪个页面的代码

升级html-webpack-plugin版本

多页面出现内存溢出的问题是因为在编译的时候,实际是一次更改,编译了多个文件,这是html-webpack-plugin的问题。因为没生成一个页面,就需要调用一下new htmlWebpackPlugin(),多个页面的时候内存就不够用了。所以改一下这个这个webpack插件的版本,升级到4.0.0-beta.8这个版本。然后再vue.config.js中添加下面的配置,这样也不会造成内存溢出。

const htmlPlugins = [];
Object.keys(multiPageConfig).forEach((key) => {
  htmlPlugins.push(multiPageConfig[key])
})
configureWebpack: {
  plugins: [
   ...htmlPlugins,
  ],
}

其他加快编译的技巧

webpack的插件还是很方便的,网上有啥happypack类似的插件。由于运行在 Node.js 之上的 Webpack 是单线程模型的,所以Webpack需要处理的事情需要一件一件的做,不能多件事一起做。

我们需要Webpack能同一时间处理多个任务,发挥多核CPU电脑的威力,HappyPack就能让Webpack 做到这点,它把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。可能是我电脑太烂了,装上没啥太大的提升,具体使用方法可以参照这篇文章webpack优化之HappyPack 实战。还有一些细节的地方比如说有些包需要加入编译,但是一般我们在调试的时候只需要在chrome上进行调试,开发环境就不用加入编译,多处使用的代码单独打包,这些也就不说了,大家多多尝试

这几种解决多页面内存溢出的方法各有优缺点,读者可根据自己的项目自行决定使用哪种方法,可能有时还需要多种方式组合使用,就看看那个好使好用了。

解决这个问题顺便研究了一下webpack,配置果然博大精深,难怪市面有流传webpack配置工程师。推销一波自己的github最近在抓紧学习,会持续更新文章,希望大家多多关注。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery 连续列表实现代码
Dec 21 Javascript
jquery实现图片裁剪思路及实现
Aug 16 Javascript
javascript正则表达式之search()用法实例
Jan 19 Javascript
JS+CSS模拟可以无刷新显示内容的留言板实例
Mar 03 Javascript
js插件dropload上拉下滑加载数据实例解析
Jul 27 Javascript
Js调用Java方法并互相传参的简单实例
Aug 11 Javascript
JavaScript实现图片瀑布流和底部刷新
Jan 02 Javascript
React Native AsyncStorage本地存储工具类
Oct 24 Javascript
Vue Echarts实现可视化世界地图代码实例
May 07 Javascript
微信小程序授权登录解决方案的代码实例(含未通过授权解决方案)
May 10 Javascript
微信小程序个人中心的列表控件实现代码
Apr 26 Javascript
jQuery实现移动端下拉展现新的内容回弹动画
Jun 24 jQuery
javascript简单实现深浅拷贝过程详解
Oct 08 #Javascript
webpack HappyPack实战详解
Oct 08 #Javascript
简单了解vue中的v-if和v-show的区别
Oct 08 #Javascript
在Koa.js中实现文件上传的接口功能
Oct 08 #Javascript
vue-cli和v-charts实现可视化图表过程解析
Oct 08 #Javascript
vue路由传参页面刷新参数丢失问题解决方案
Oct 08 #Javascript
vux-scroller实现移动端上拉加载功能过程解析
Oct 08 #Javascript
You might like
PHP通过header实现文本文件下载的代码
2010/08/08 PHP
php UBB 解析实现代码
2011/11/27 PHP
php中is_null,empty,isset,unset 的区别详细介绍
2013/04/28 PHP
php实现的debug log日志操作类实例
2016/07/12 PHP
YII2 实现多语言配置的方法分享
2017/01/11 PHP
浅谈Laravel POST,PUT,PATCH 路由的区别
2019/10/15 PHP
PHP如何使用array_unshift()在数组开头插入元素
2020/09/01 PHP
数理公式,也可以这么唯美
2021/03/10 无线电
javascript 进阶篇3 Ajax 、JSON、 Prototype介绍
2012/03/14 Javascript
js选取多个或单个元素的实现代码(用class)
2012/08/22 Javascript
悬浮数字的实现案例
2014/02/19 Javascript
jQuery老黄历完整实现方法
2015/01/16 Javascript
jQuery动画效果相关方法实例分析
2015/12/31 Javascript
Angular.js中ng-if、ng-show和ng-hide的区别介绍
2017/01/20 Javascript
vue-router路由参数刷新消失的问题解决方法
2017/06/17 Javascript
JS实现新建文件夹功能
2017/06/17 Javascript
EasyUI创建人员树的实例代码
2017/09/15 Javascript
解决VUE框架 导致绑定事件的阻止冒泡失效问题
2018/02/24 Javascript
详解Immutable及 React 中实践
2018/03/01 Javascript
vue.js 中使用(...)运算符报错的解决方法
2018/08/09 Javascript
vue element自定义表单验证请求后端接口验证
2019/12/11 Javascript
Python数据结构与算法之图的广度优先与深度优先搜索算法示例
2017/12/14 Python
Python创建一个空的dataframe,并循环赋值的方法
2018/11/08 Python
python write无法写入文件的解决方法
2019/01/23 Python
Python Tornado批量上传图片并显示功能
2020/03/26 Python
Python虚拟环境的创建和包下载过程分析
2020/06/19 Python
html5 制作地图当前定位箭头的方法示例
2020/01/10 HTML / CSS
伊莱克斯阿根廷网上商店:Tienda Electrolux
2021/03/08 全球购物
2013年保送生自荐信格式
2013/11/20 职场文书
煤矿班组长岗位职责
2013/12/29 职场文书
校园文明倡议书
2014/05/16 职场文书
学生党支部工作总结2015
2015/05/26 职场文书
歌舞青春观后感
2015/06/10 职场文书
生活委员竞选稿
2015/11/21 职场文书
2016国培研修心得体会
2016/01/08 职场文书
vue使用refs获取嵌套组件中的值过程
2022/03/31 Vue.js