>  기사  >  웹 프론트엔드  >  웹팩 프런트엔드 성능 최적화 정보(자세한 튜토리얼)

웹팩 프런트엔드 성능 최적화 정보(자세한 튜토리얼)

亚连
亚连원래의
2018-06-22 17:08:132224검색

Webpack은 최근 가장 인기 있는 모듈 로더이자 패키징 도구입니다. JS(JSX 포함), 커피, 스타일(less/sass 포함), 이미지 등 다양한 리소스를 모듈로 사용하고 처리할 수 있습니다. 이 글은 웹팩 학습 튜토리얼의 프론트엔드 성능 최적화에 대한 관련 정보를 주로 요약하고 소개합니다.

머리말

옛날에는 위와 같이 JS 리소스를 소개했지만 지금은 거의 볼 수 없는 것 같습니다. 최근 몇 년 동안 웹 프런트엔드 개발 분야는 표준화된 개발 방향으로 발전해 왔습니다. 이는 다음 두 가지 사항에 반영됩니다.

1. MVC R&D 아키텍처. 많은 이점(명확한 논리, 프로그램은 데이터와 성능의 분리, 강력한 가독성에 중점을 두어 문제를 방지하고 해결하는 데 도움이 됩니다...)

2. 끝없는 구성 도구가 있습니다. 많은 이점(팀 협업 및 엔지니어링 운영 및 유지 관리 개선, 사소하고 반복적인 작업의 수동 처리 방지)

  • 모듈식 개발

  • 프론트 엔드 성능 최적화 이론 구현, 코드 압축, 병합, 캐시 제어, 공개 코드 추출 잠깐

  • 기타에는 예를 들어 ES 6 또는 CoffeeScript를 사용하여 소스 코드를 작성한 다음 브라우저에서 지원하는 ES5를 빌드할 수 있습니다

그래서 아직 프로젝트가 있으면 프런트엔드가 너무 재미있습니다. 프런트엔드와 백엔드를 분리하지 않으면 정말 너무 보수적입니다.

주요 빌드 도구

Grunt, Gulp, browserify 등을 포함하여 시장에는 많은 빌드 도구가 있습니다. 이러한 도구와 WebPack은 모두 패키징 도구입니다. 하지만 WebPack에는 다음과 같은 특징도 있습니다.

Grunt에 비해 WebPack은 풍부한 플러그인 세트뿐만 아니라 로딩(로더) 시스템도 갖추고 있습니다. Grunt 및 Gulp에는 없는 ES6, CommonJS, AMD 등을 포함한 여러 표준 로딩 방법을 지원하도록 만드세요.

코드 난독화의 관점에서 보면 WebPack은 훨씬 더 극단적입니다.

코드는 파일이 아닌 처리 단위로 조각화되어 파일 조각화를 더욱 유연하게 만듭니다.

P.S. 어느 쪽이 더 좋고 나쁨에 관계없이 단순한 비교입니다. 실제로 모든 도구가 요구 사항을 충족할 수 있습니다. 도구 사용 방법 뒤에는 프런트 엔드 성능 최적화에 대한 이해가 있습니다.

소개

최근 첫 화면 로딩 성능을 최적화하기 위해 webpack을 사용하고 있는데, 여러 플러그인을 사용한 후 온라인 접속 전후 속도가 두 배로 빨라졌습니다. 최적화 전, 후 첫 화면 렌더링 비교 이미지입니다.

총 다운로드 시간이 3800ms에서 1600ms로 줄어든 것을 확인할 수 있습니다.

webpack을 사용할 때 우리는 일반적으로 자체 소스 코드와 타사 라이브러리 코드를 분리하기 위해 다중 항목 파일을 선택합니다. 이전 코드입니다.

entry: {
 entry: './src/main.js',
 vendor: ['vue', 'vue-router', 'vuex', 'element-ui','echarts']
},
output: {
 path: config.build.assetsRoot,
 filename: utils.assetsPath('js/[name].[chunkhash].js'),
 chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
}

echarts는 용량이 매우 커서 패키징된 Vendor.js가 약 1.2MB(gzip 압축 후)이고, 홈페이지에서는 echarts를 사용하지 않아서 나중에 외부를 사용하여 타사를 가져옵니다. library to cdn을 소개하자면 다음은 최적화된 코드입니다

entry: {
 entry: './src/main.js',
 vendor: ['vue', 'vue-router', 'vuex', 'element-ui']
 },
 // 这里的output为base中的output,不是生产的output
 output: {
 path: config.build.assetsRoot,
 filename: '[name].js',
 libraryTarget: "umd",
 publicPath: process.env.NODE_ENV === 'production' ?
  config.build.assetsPublicPath : config.dev.assetsPublicPath
 },
 externals: {
 echarts: 'echarts',
 _: 'lodash'
 },

최적화 전과 후의 비교입니다.

그런 다음 HTML로 이동하여 스크립트 태그 형식으로 외부의 CDN을 인용해야 합니다. 그 후에는 해당 파일로 가져올 수 있습니다. 여러 vue 파일에서 아무리 많이 참조하더라도 모든 트렁크에 패키징되지 않는다는 장점이 있습니다. (여기서 트렁크는 요청 시 로드되는 것을 의미합니다. 자세한 내용은 나중에 설명), 이는 webpack-bundle-analyzer 플러그인을 사용하여 표시되는 효과입니다.

var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
new BundleAnalyzerPlugin({
  // 可以是`server`,`static`或`disabled`。
  // 在`server`模式下,分析器将启动HTTP服务器来显示软件包报告。
  // 在“静态”模式下,会生成带有报告的单个HTML文件。
  // 在`disabled`模式下,你可以使用这个插件来将`generateStatsFile`设置为`true`来生成Webpack Stats JSON文件。
  analyzerMode: 'server',
  // 将在“服务器”模式下使用的主机启动HTTP服务器。
  analyzerHost: '127.0.0.1',
  // 将在“服务器”模式下使用的端口启动HTTP服务器。
  analyzerPort: 8888, 
  // 路径捆绑,将在`static`模式下生成的报告文件。
  // 相对于捆绑输出目录。
  reportFilename: 'report.html',
  // 模块大小默认显示在报告中。
  // 应该是`stat`,`parsed`或者`gzip`中的一个。
  // 有关更多信息,请参见“定义”一节。
  defaultSizes: 'parsed',
  // 在默认浏览器中自动打开报告
  openAnalyzer: true,
  // 如果为true,则Webpack Stats JSON文件将在bundle输出目录中生成
  generateStatsFile: false, 
  // 如果`generateStatsFile`为`true`,将会生成Webpack Stats JSON文件的名字。
  // 相对于捆绑输出目录。
  statsFilename: 'stats.json',
  // stats.toJson()方法的选项。
  // 例如,您可以使用`source:false`选项排除统计文件中模块的来源。
  // 在这里查看更多选项:https: //github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
  statsOptions: null,
  logLevel: 'info' //日志级别。可以是'信息','警告','错误'或'沉默'。
 })

eccharts 및 lodash와 같은 라이브러리는 외부 요소가 없거나 외부 요소를 사용한 후에는 모든 js에 나타나지 않는 것을 볼 수 있습니다(10,000번 가져오더라도 한 번만 패키징되지는 않습니다. 멋지네요~~ ).

외부 항목에 대한 두 가지 추가 사항 -

1. 외부 항목의 키는 가져오기에 사용됩니다.

import lodash from "_";
import echarts from "echarts";

2. 외부 항목의 값은 창 아래에 호출됩니다.

그런 다음 출력이 트렁크 해시를 사용하는 이유에 대해 이야기해 보겠습니다. , 이는 지속적인 캐싱을 위한 것입니다. 둘의 차이점을 간단히 얘기해보자 -

트렁크: 각 빌드 이후의 버전은 빌드 이후의 모든 파일의 해시값이 동일하다는 뜻이다. 예를 들어 파일 하나만 변경하면 모든 파일이 해시된다. 결국 모든 파일이 캐시되지 않도록 변경되므로 캐시는 의미가 없게 됩니다.

trunkhash: 각 파일을 기반으로 서로 다른 해시 값을 생성합니다. 파일이 변경되면 해시도 변경되고 해당 파일만 변경됩니다

然后我们肯定是要用到CommonsChunkPlugin,这个插件是用来抽取公共代码的,基本上99%的配置都是长这样子或者类似这样子用两个不同的commonschunkPlugin,但这从某方面来说并没有实现真正意义上的持久化缓存,这个一会我会通过webpack打包原理来详细解释其中的原因。。。。。。

new webpack.optimize.CommonsChunkPlugin({
 names: ['vendor','manifest']
})

在没用这个插件之前,我们的main.js和vendor.js会是这样子。。。

大家会看到我们这两个文件会有公共的部分,比如vue和element-ui,所以我们要抽取公共代码到vendor中,所以我们可以先这样配置

new webpack.optimize.CommonsChunkPlugin({
 name: 'vendor',
}),

但这样的话虽然可以提取公共代码,但我们会把runtime(webpack运行时的代码,一会在打包原理中会再次提到)也放到vendor中,这里面会维护一个trunk的文件列表,类似于这样,就是说我们改任意的代码,这个table里面的hash会变,所以vendor的hash也会变

,所以这没有实现真正的持久化缓存。这个hash table是按需缓存的打包出来的trunk包,一般都是通过require.ensure(就是vue-router中配置的page对应页面,按需加载)

所以我们就把name改为names,就是上面那个配置。因为使用这个插件,我们会把公共代码抽到第一个name中,把runtime放到最后一个name中,也就是我们所谓的“manifest”文件。

并且这个文件会比较小,通常都是2kb左右,所以build后会生成一个script标签,但这样的话就多了一个http请求,所以我们可以用另外一个插件(InlineManifestWebpackPlugin)将manifest.js内联进去。就会长这样子

再回到我们的CommonsChunkPlugin,现在我们随便改任何已存在的文件,vendor.js的hash都不会变,是的,貌似这就实现了持久化缓存。但是当我们新增一个模块,并且在入口文件中import一下,我们的vendor就会跟main一起变。很奇怪对吧,我们明明已经做了自己的源码跟第三方库分离,为什么vendor还会变(到现在应该没有任何一篇博客对此进行详细的说明)。下面我就详细的给大家解释下我的看法,如果大家发现有不对的地方还请指正。

再解释为什么之前,我们先简单了解下webpack的打包规则。

webpack一个entry对应一个bundle,这个bundle包括入口文件和其依赖的模块。其他按需加载的则打包成其他的bundle。还有一个比较重要的文件时manifest,它是最先加载的,负责打包其他的bundle并按需加载和执行。

manifest是一个自执行函数,熟悉angular的同学看第一行应该很了解,因为anguar1.3版本的源码中启动就是angular.bootstrap,对,这里也是一样。里面的modules变量就是对应模块函数,它是webpack处理的基本单位,就是说对应打包前的一个文件

这是js源文件,

这是打包后的文件,

所有的模块函数索引都是连续的(每个js文件生成一个trunkid!!!!!),像这种 /* 4 */ 对应的就是js文件,他通过打包就变成了一个个trunkid,仔细看会看到咱们打包前js文件里的export和require依赖都会统一转换成webpack模块。咱们说的webpackJsonp就是除manifest之外打包其他的文件的函数体。

简单说下main吧,这个图的trunkid是连续的,为了在一张图上显示,我截掉了trunk3-7.

这里面一共有三个参数,第一个是我当前文件的trunkid,它是唯一标识符,就是指main的trunkid,第二个就是打包的所有文件的模块函数,第三个是我要立即执行的trunkid模块函数。

ok,介绍这些就足够了。

然后我们再回过头来看看为什么我们所谓的commonschunkPlugin会变。刚才说过,有几个js就有几个trunkid。

그래서 새 js를 추가하고 이를 메인 항목에 도입하면 webpack이 이를 다시 패키징하고, 내 메인 파일은 방금 말했듯이 트렁크 ID가 순차적으로 증가하고 반복되지 않습니다. 따라서 해당 공급업체의 ID는 +1이 됩니다. 해시가 변경되는 미묘한 변화입니다.

두 공급업체 모두 10272개의 라인을 가지고 있습니다. 유일한 차이점은 여기서 jquery를 인용했기 때문에 이 파일에는 self.jquery만 있습니다. -실행 중입니다. 모듈 함수인 trunkid+1이 있어야 하므로 해시가 변경됩니다. 사실, 이것은 또한 이 플러그인의 중요성을 보여줍니다. 저는 단지 공용 라이브러리를 추출하고 싶습니다. 이 플러그인은 이를 수행하지만 웹팩 패키징 메커니즘으로 인해 서로 다른 턴키드가 생성됩니다. , 그래서 이것은 연고 속의 파리입니다. 일반적으로 main.js를 임의로 수정하지 않는다는 점을 기억하세요. 따라서 다른 관점에서 보면 이는 영구 캐싱의 구현입니다. 하지만 공급업체의 해시를 변경하지 않고 그대로 유지하고 싶다면 어떻게 해야 할까요?

이 코드는 구현 가능합니다. 예, vue-cli를 잘 아시는 분이라면 이것이 vue-cli 공식 데모에서 설명드리겠습니다. 쓰지 마세요) .

마지막으로 아주 유용한 것, 바로 CDN을 소개해 드리겠습니다. 현재 우리의 요구는 사진을 CDN 및 js로 이동하여 온라인으로 이동시키는 것입니다. 그러나 공식적인 설명은 구성 파일을 수정하여 CDN을 변경하는 것입니다. 이 작업이 완료되면 모든 출력이 CDN을 통과하고 모든 Ajax 요청이 수행됩니다. 예, 크로스 도메인이 될 것입니다.

처음에 제가 해결한 방법은 소스 파일을 하나씩 교체하는 것이었습니다. 더 중요한 것은 CDN 이미지에도 해시 값이 있으므로 나중에 이미지를 교체해야 한다는 것입니다. 따라서 해시. 자동으로 해시를 얻을 수 있는 방법이 있나요?

예, js가 온라인 경로에 액세스하고 정적 리소스가 CDN을 사용할 수 있도록 url-loader에서 CDN을 별도로 구성해야 합니다. 둘은 서로 영향을 미치지 않습니다.

알아두세요. url-loader는 js의 배경을 감지할 수 없으므로 js에서 참조하는 모든 주소는 먼저 이미지를 외부로 가져와야 하며 그런 다음 url-loader가 이를 구문 분석하고 패키지합니다.

위 내용은 제가 여러분을 위해 정리한 내용입니다. 앞으로 도움이 되길 바랍니다.

관련 기사:

WeChat 애플릿에서 비디오를 재생하기 위해 비디오 구성 요소를 사용하는 방법

WeChat 애플릿에서 오디오 구성 요소를 사용하는 방법

vue에서 axios 보조 캡슐화를 구현하는 방법

위 내용은 웹팩 프런트엔드 성능 최적화 정보(자세한 튜토리얼)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.