热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

webpack性能优化(下)

通常来说,我们会通过使用file-loader,url-loader等loader来处理项目中的静态

在webpack性能优化(上) 中,我们从 代码分离,Loader, webpack解析(resolve), webpack 外部扩展(Externals) ,Dlls 优化构建速度,等方面分析了优化手段,这篇文章让我们接着来撸。

图片等静态文件 dev prod

通常来说,我们会通过使用file-loader,url-loader等loader来处理项目中的静态文件,如图片字体等文件

//这样最终dist文件中就会生成font文件夹存放字体文件
{
    test: /\.(woff|svg|eot|ttf)\??.*$/,
    loader: "url-loader",
    options: {
        limit: 8192,
        name: "font/[name].[hash:6].[ext]"
    }
}

limit属性是在文件大小超出limit的值才会单独打包,否则使用base64 的方式引用通常适用于小图片,这就是我们通常的文件处理方式。

使用base64引入图片的好处是减少http请求数,但相应的问题是base64占用的空间比普通的图片文件大一点。

当然我们还有另外一种方案,具体做法是将项目的中静态文件统一存放在static文件夹下,最后使用 CopyWebpackPlugin将static文件夹拷贝到dist目录下

new CopyWebpackPlugin([
    {
        from: path.resolve(SRC_PATH, 'img'),
        to: 'img'
    }
]),

这样做的好处是我们的静态资源不经过webpack的处理,可以提升构建速度,但问题也是很明显的,那就是维护的成本增大并可能出现一些意外的情况,比如:

这样处理的问题是可能开发环境引用路径和打包文件访问图片路径不一致问题,这里可以通过output.publicPath属性来配置解决

output: {
    //打包文件中通过相对路径引用的资源都会被配置的路径所替换
    publicPath: '/assets/'
}

//对于这种结构的项目当然不合适使用这种方法
|- /static
|– /components
|  |– /my-component
|  |  |– index.jsx
|  |  |– index.css
|  |  |– icon.svg
|  |  |– img.png

当然从我们实际项目的测试效果来看,我只能说这种处理方式并不算是很优秀,仅供参考。

source map dev

在开发环境中,我们比较关注调试的方便程度,而原始webpack打包后的bundle文件中可能包含来自多个文件的内容,对于程序的报错信息往往简单的指向这个bundle文件:

webpack性能优化(下)

而source map是为了帮助我们定位程序出现的错误对应的源代码的位置。使用sourceMap报错信息正确的指向了源码的错误位置。

webpack性能优化(下)
//1 使用devtool选项配置,有多个选项可选
module.exports = {
    devtool: 'inline-source-map',
};

//2 使用plugins方式进行更细粒度的配置
module.exports = {
    plugins: [
        new webpack.SourceMapDevToolPlugin({
            filename: '[name].js.map',
            exclude: ['vendor.js']
        })
    ]
};

//在使用uglifyjs-webpack-plugin时 需要开启sourceMap选项

devtool文档

UglifyJsPlugin 配合 tree shaking prod

对于js压缩 在webpack <= 3.x的版本中:

//1 使用 -p(production)标记来压缩js
//2 使用内置 plugin(webpack.optimize.UglifyJsPlugin)
//3 使用外部引入plugin(uglifyjs-webpack-plugin)
module.exports = {
    plugins: [
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            },
            output: {
                //remove all comments
                comments: false
            }
        }),
    ]
};

在webpack4中

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
    //1 设置 mode
    mode: ""production
    //2 minimize
    optimization:{
	minimize: true,
        //3 或者指定其他插件
        minimizer: [
          new UglifyJsPlugin({
            sourceMap: true
          })
        ]
    },
    //3 若需要sourceMap 需要设置 devtool的值
    devtool: 'source-map', 
};

//可选的压缩插件
UglifyJSPlugin, ClosureCompilerPlugin
BabelMinifyWebpackPlugin,

此处需要注意。若是在使用了UglifyJSPlugin且开启sourceMap后,需要同时给devtool设置值。同样的若是设置了devtool的值,则UglifyJSPlugin也需要开启sourceMap。否则不会生成.map的源代码对应文件。

在开启js的压缩后 我们的tree shaking登场了,tree shaking是什么?为什么需要使用?

tree shaking是一个术语,用于描述移除js中未引用的代码。 使用它能优化输出。 未开启tree shaking的实例:

//tool.js
export function square(x) {
  return x * x;
}

export function cube(x) {
  return x * x * x;
}

//index.js
import { square } from "./tool.js"

//最终输出  在关闭 UglifyJSPlugin插件后测试结果
webpack性能优化(下)

我们可以看到 cube这个我们并没有引用的模块也被打包进源码了。

使用tree shaking 来优化输出,在package.json中:

//webpack4
//1 将文件标记为无副作用 
{
  "name": "web",
  "version": "1.0.0",
  //若是整个项目都无副作用 直接设置为false
  "sideEffects": false
  //若是部分文件确实有副作用
  "sideEffects": [file_path1, file_path2]
}

//2 开启js压缩 使用上述方法开启即可

//webpack2/3
//1 需要配置 .babelrc modules false
{
  "presets": [
    [
      "env", 
      {
        "modules": false
      }
    ]
  ]
}

//2 开启js压缩

「副作用」的定义是,在导入时会执行特殊行为的代码,而不是仅仅暴露一个 export 或多个 export。举例说明,例如 polyfill,它影响全局作用域,并且通常不提供 export。

对于开启后的压缩代码中,我们搜索"*"号 只得到一个结果,测试成功。

webpack性能优化(下)

最后我们简单解释下设置modules false的作用。tree shaking本身是依赖于ES6的静态导入,也就是我们常用的import export。ES6模块化中一个文件能够输出多个模块,而我们可以只导入需要的模块。对比commonjs的动态导入模块化标准,一个文件只有一个输出,因此不难发现,tree shaking在commonjs模块化的系统中是发挥不了作用的。

而modules的意义是启用将ES6模块语法转换为另一种模块类型,默认值'commonjs',将该设置为false即不转化,也就是ES6模块语法,所以在此我们需要将modules设置为false。

modules的取值有 'amd' | 'umd' | 'systemjs' | 'commonjs' | false。 在webpack4中已经可以不用此方法来检测重复模块了

Split CSS prod

一个web项目中css是关键的一环,若没有额外配置css最终会被打包进入js文件中,但熟悉浏览器渲染的开发者应该会清楚,浏览器在渲染页面时会解析DOM树和CSS树,最后将之对应合并呈现渲染好的页面。将css放在js中引入势必会延缓css树的计算。 所以将css从js中分离,打包成单独的css文件,然后和js并行加载是我们项目的一个提升点,这样可以加快界面渲染速度,也可以单独做缓存。

//使用插件 extract-text-webpack-plugin
{
    test: /\.css$/,
    use: ExtractTextPlugin.extract({
        //用于css未被提取(allChunks: false)
        fallback: "style-loader",
        use: 'css-loader'
    })
}

new ExtractTextPlugin({
    filename: 'common.[chunkhash].css',
    allchunk: true
})

当然webpack-dev-server是不支持extract-text-webpack-plugin抽离的css热替换的,所以此插件不建议再dev环境中使用,如果非要使用可以考虑css-hot-loader。

清理 /dist 文件夹 prod

webpack将打包的文件放在dist文件夹中,若是使用了hash文件名,则每次文件变动后重新打包生成的文件名都会不同,这会造成dist目录越来越混乱,好的做法是每次打包前先清理dist文件夹:

new CleanWebpackPlugin(pathsToClean, cleanOptions)

在内存中编译 dev

webpack-dev-server大家都不陌生,开发环境必备,webpack内部依赖了webpack-hot-middleware,webpack-dev-middleware两个插件。

webpack-dev-middleware提供了在内存中编译功能,它在文件更改后自动编译文件并保存在内存中,具体表现为,刷新浏览器即可看到我们的更改。

webpack-hot-middleware提供了服务端推送功能,通常和webpack-dev-middleware配合使用,当文件更改并自动编译完成后,服务端通过SSE(服务端发送事件)将更改信息推送到客户端,客户端会接收到一个json文件,其中包含了更改了的文件的一些信息,客户端会根据这些信息主动向服务端获取最新的文件。

若无文件更改webpack-hot-middleware也会在一定时间间隔后遍历内存文件检测是否更改,然后通过事件流的方式向客户端发送消息。

webpack-dev-middleware和webpack-hot-middleware都是express的标准插件

我相信各位项目中这两个功能都是已经开启的我就不再具体说他们的配置了,这里我们主要说下在node服务端怎么使用这两个插件达到热更新的目的。

我们以koa为例,如何在koa中开启热更新调试我们的项目呢?

//新建 app.js作为koa服务端入口 app.js

import Koa from "koa";
import views from "koa-views";
import webpack from "webpack";
import webpack_config from "../webpack/webpack.config.js";
import { devMiddleware, hotMiddleware } from 'koa-webpack-middleware'

var app = new Koa()
var compiler = webpack(webpack_config)

app.use(views("./template", {map: {html: "ejs"}}));

app.use(devMiddleware(compiler,{
    publicPath:"/"
}));

app.use(hotMiddleware(compiler))

koa-webpack-middleware 将express的中间件(webpack-dev-middleware和webpack-hot-middleware)进行封装,将我们koa中间件的next方法传递到express的第三个参数中进行封装。

最简单的配置如上。但这种配置会有一个问题就是刷新404的问题。

hotMiddleware会在匹配到项目跟路由时直接返回内存中的html文件给客户端。但是其他的路由如react的路由时,它不会去匹配,最终会返回一个404

//会返回template/index.html 但这时是空的
//也就是没有导入js的html
await ctx.render("index");

解决,当用户访问时在webpack编译输出的最后阶段获取到文件信息,取出获取到的html文件写入template下的index.html文件,最后返回它,具体操作如下:

compiler.plugin("emit",(comilation,callback) => {
    const assets = comilation.assets;
    let file, data;
    Object.keys(assets).forEach(key => {
        if(key.match(/\.html$/)){
            file = path.resolve(__dirname,"./template/index.html");
            data = assets[key].source();
            fs.writeFileSync(file,data);
        }
    });

    callback();
})

当然上述方法略显笨重,且需要理解的东西较多,不太推荐,这里有一个插件能解决上述问题 connect-history-api-fallback,大家自己学习下即可。

我的博客地址


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 我们


推荐阅读
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 本文介绍了在Python中使用zlib模块进行字符串的压缩与解压缩的方法,并探讨了其在内存优化方面的应用。通过压缩存储URL等长字符串,可以大大降低内存消耗,虽然处理时间会增加,但是整体效果显著。同时,给出了参考链接,供进一步学习和应用。 ... [详细]
  • 本文介绍了OkHttp3的基本使用和特性,包括支持HTTP/2、连接池、GZIP压缩、缓存等功能。同时还提到了OkHttp3的适用平台和源码阅读计划。文章还介绍了OkHttp3的请求/响应API的设计和使用方式,包括阻塞式的同步请求和带回调的异步请求。 ... [详细]
  • 1223  drf引入以及restful规范
    [toc]前后台的数据交互前台安装axios插件,进行与后台的数据交互安装axios,并在main.js中设置params传递拼接参数data携带数据包参数headers中发送头部 ... [详细]
  • 翻译 | 编写SVG的口袋指南(上)
    作者:DDU(沪江前端开发工程师)本文是原文翻译,转载请注明作者及出处。简介ScalableVectorGraphics(SVG)是在XML中描述二维图形的语言。这些图形由路径,图 ... [详细]
  • higuysihaveproblemwithtreeshakinginnx,problemwithassetslibrary ... [详细]
  • 今天周六,原则上要休息,但想到下周还有一堆任务,还是先做一部分工作吧,就把之前做的票面设计器改了改,增加了上传图片和更换背景底图的功能。现在打算整理下这个设计器,也算对齐一个总结。不过这属于我们部门的 ... [详细]
  • webui之常用js操作(webui界面是什么)
    本文目录一览:1、web前端开发需要掌握的几个必备技术 ... [详细]
  • 前端性能优化无损压缩webp格式的图片
    一、什么是webpWebP格式,谷歌开发的一种旨在加快图片加载速度的图片格式。图片压缩体积大约只有JPEG的23,并能节省大量的服务器宽带资源和数据空 ... [详细]
  • Redis底层数据结构之压缩列表的介绍及实现原理
    本文介绍了Redis底层数据结构之压缩列表的概念、实现原理以及使用场景。压缩列表是Redis为了节约内存而开发的一种顺序数据结构,由特殊编码的连续内存块组成。文章详细解释了压缩列表的构成和各个属性的含义,以及如何通过指针来计算表尾节点的地址。压缩列表适用于列表键和哈希键中只包含少量小整数值和短字符串的情况。通过使用压缩列表,可以有效减少内存占用,提升Redis的性能。 ... [详细]
  • 用JavaScript实现的太空人手表
    用JavaScript实现的太空人手表-JS写的太空人手表,没有用canvas、svg。主要用几个大的函数来动态显示时间、天气这些。天气的获取用到了AJAX请求。代码中有详细的注释 ... [详细]
  • 电脑桌面管理软件_电脑文件一团乱?试试这 8个高效率的管理软件,批量管理!...
    随着工作的时候越来越长,如山的文件挤满电脑,让人很头疼。不知道你有没有遇到这些烦恼?桌面堆满文件,想整理却又无从下手 ... [详细]
  • 小程序引入外部文件的方式是:import**.wxss;因为业务需要,正在开发的小程序中需要使用iconfont,很容易想到了H5的引 ... [详细]
author-avatar
小丸子2502856277_253
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有