>웹 프론트엔드 >JS 튜토리얼 >웹팩 캐싱 및 독립 패키징 사용에 대해

웹팩 캐싱 및 독립 패키징 사용에 대해

巴扎黑
巴扎黑원래의
2017-08-06 15:07:031181검색

이 글은 webpack의 고급 활용법인 캐싱과 독립 패키징을 주로 소개합니다. 편집자는 꽤 좋다고 생각해서 지금 공유하고 참고용으로 올려보겠습니다. 에디터를 따라가서 살펴보도록 하겠습니다

이 글에서는 웹팩의 고급 사용법인 캐싱과 독립 패키징을 소개합니다. 모든 분들께 도움이 되길 바랍니다

가장 기본적인 웹팩 구성을 살펴보겠습니다. 첫 번째:


var path = require('path');
 
module.exports = {
 entry: './src/index.js',
 output: {
  filename: 'bundle.js',
  path: path.resolve(__dirname, 'dist')
 }
}

는 index.js에 lodash 라이브러리를 도입했습니다.

src/index.js:


import _ from 'lodash';
 
 function component() {
  var element = document.createElement('p');
  element.innerHTML = _.join(['Hello', 'webpack'], ' ');
 
  return element;
 }
 
 document.body.appendChild(component());

패키징 후에는 매번 하나의 Bundle.js만 생성됩니다. 리소스 파일을 로드하려면 찾아보세요. 서버는 전혀 변경되지 않는 lodash 라이브러리를 로드하므로 이는 매우 비효율적입니다.

브라우저를 방문할 때마다 브라우저가 리소스를 다시 다운로드하기 때문에 네트워크가 리소스를 얻는 데 시간이 오래 걸릴 수 있으므로 페이지가 오랫동안 로드되지 않을 수 있으며 이는 비효율적이고 비친화적입니다. 브라우저는 리소스를 캐시하여 매번 방문할 때마다 네트워크를 통해 리소스를 얻습니다.

하지만 브라우저 캐싱으로 인해 새로운 문제가 발생할 수 있습니다. 버전을 배포할 때 리소스의 파일 이름을 변경하지 않으면 브라우저는 업데이트되지 않은 것으로 간주하여 캐시된 버전을 사용할 것입니다.

그래서 우리는 두 가지 문제를 해결해야 합니다. 먼저, 패키지 파일을 분리합니다. 둘째, 캐싱 문제를 해결하세요.


const path = require('path');
const webpack = require('webpack');
 
module.exports = {
 entry: {
  common: ['lodash'],
  app: './src/index.js'
 },
 output: {
  filename: '[name].[hash].js',
  path: path.resolve(__dirname, 'dist')
 },
 plugins: [
  new webpack.optimize.CommonsChunkPlugin({
   name: 'common' // 指代index.js引入的lodash库
  })
 ]
}

주요 변경 사항:

  • 플러그인 추가: CommonsChunkPlugin, 가져온 라이브러리를 추출하고 이름을 변경하여 코드 분리를 구현합니다.

  • 각 패키지마다 해시 값이 출력의 이름에 추가되어 브라우저 캐싱 문제가 해결됩니다.

결과: index.js는 app.[hash].js로 패키징되어 있고, index.js가 도입한 lodash는 common.[hash].js로 패키징되어 있습니다. 이는 브라우저 캐시 문제를 해결하고 정적 리소스 코드와 소스 코드의 분리를 달성하지만 새로운 문제가 다시 발생합니다.

첫 번째 패키징 후(자산 열 아래 이름 참고):

소스 코드를 수정하고 다시 패키징할 때마다 인덱스 생성 앱의 해시 값뿐만 아니라.[hash].js 변경되지만

게다가 common.[hash].js의 해시 값이 앱의 해시 값과 동일하고 변경되었습니다. (직접 테스트할 수 있으며 먼저 webpack으로 한 번 패키징합니다. , index.js를 수정하고 다시 패키징하세요).

이것은 우리가 원하는 결과가 아닙니다. 소스 코드 해시 변경으로 캐시된 버전을 사용하는 브라우저의 문제가 해결되지만 common.js의 해시 값도 변경되면 브라우저도 이를 매번 변경해야 합니다. 모두 변경되지 않는 공통 정적 코드를 요청하는데, 이는 여전히 네트워크 리소스를 낭비하고 매우 비효율적입니다.

참고: 이 케이스는 여러 번 패키징되며 dist 디렉터리에 너무 많은 정크 파일이 생성됩니다. 실제 사용에서는 CleanWebpackPlugin 플러그인이 사용됩니다.

코드 복사 코드는 다음과 같습니다.


new CleanWebpackPlugin(['dist']) // 각 패키징 전에 패키징 폴더에서 이전에 패키징된 파일을 지우려면 플러그인 배열에 추가합니다.

인덱스가 수정되면 생성된 앱의 해시 값만 변경되고 공통의 해시 값은 변경되지 않으므로 라이브러리를 캐시하고 소스의 변경 사항을 식별할 수 있는 목적을 달성할 수 있습니다. 파일.
다음을 구성합니다. 출력의 [name].[hash].js를 [name].[chunkhash].js로 변경하여 각 파일이 고유한 해시 값을 생성하도록 합니다.


const path = require('path');
const webpack = require('webpack');
 
module.exports = {
 entry: {
  common: ['lodash'],
  app: './src/index.js'
 },
 output: {
  filename: '[name].[chunkhash].js',
  path: path.resolve(__dirname, 'dist')
 },
 plugins: [
  new CleanWebpackPlugin(['dist']),
  new webpack.optimize.CommonsChunkPlugin({
   name: 'common' // 指代index.js引入的lodash库
  })
 ]
}

(참고: Don 개발 환경에서는 [chunkhash]를 사용하지 마세요. 개발 모드와 프로덕션 모드의 구성을 분리하고 개발 모드에서는 [name].js 파일 이름을 사용하고 프로덕션 모드에서는 [name].[을 사용하세요. .js 파일 이름이므로 이때 HotModuleReplacementPlugin을 사용하면 컴파일이 실패합니다! )

구성한 후 웹팩 패키징을 수행합니다.

chunkhash는 파일 내용을 기반으로 생성됩니다. app과 common에서 생성된 해시 값이 서로 다른 것을 알 수 있습니다([name].[hash].js 패키징을 사용하여 비교).

index.js를 임의로 수정하고 다시 패키징했습니다.

이상한 점은 common과 app이 별도의 해시 값을 생성하지만 index.js를 수정한 후에도 common의 해시 값이 계속 발생한다는 것입니다. 변화.

原因是:为了最小化生成的文件大小,webpack使用标识符而不是模块名称,在编译期间生成标识符,并映射到块文件名,然后放入一个名为chunk manifest的JS对象中。重点就在于!!当我们使用CommonsChunkPlugin分离代码时,被分离出来的代码(本文中的lodash库,被打包为common。),会默认被移动到entry中最后一个入口进行打包(第一个入口是index.js)。重要的是,chunk manifest将随着这些被分离出来的代码共同打包!!!

由于我们更改源代码后,不但会更新app的hash值,还会生成新的映射,然后新的映射又会和资源代码一同打包,又由于chunkhash是根据内容生成hash的,那么加入了新的映射对象chunk manifest的资源代码被打包后,hash自然也会发生改变。这反过来,产生的新hash将使长效缓存失效。

那么接下来我们需要做的就是讲 manifest分离出来。这里我们利用一个CommonsChunkPlugin一个较少有人知道的功能,能够在每次修改后的构建中将manifest提取出来,通过指定entry中未用到的名称,此插件会自动将我们需要的内容提取到单独的包中。

故再额外配置一个CommonsChunkPlugin:


const path = require('path');
const webpack = require('webpack');
 
module.exports = {
 entry: {
  common: ['lodash'],
  app: './src/index.js'
 },
 output: {
  filename: '[name].[chunkhash].js',
  path: path.resolve(__dirname, 'dist')
 },
 plugins: [
  new CleanWebpackPlugin(['dist']),
  new webpack.optimize.CommonsChunkPlugin({
   name: 'common' // 指代index.js引入的lodash库
  }),
  new webpack.optimize.CommonsChunkPlugin({
   name: 'manifest' // 用于提取manifest
  })
 ]
}

webpack打包后:

从这里可以证明之前所说的manifest被打包进了common!!!仔细看之前的图:common的Size都是547kb,到这里common大小是541kb 而manifest大小正好为5.85kb,加起来正好为547kb。

然后我们修改index.js再次打包:

从这里可以发现!!我们修改了源代码,common的hash值已经不再发生改变了!到这里可以达到我们不缓存源代码缓存资源文件的目的了。

但是可别高兴得太早!!我们做了一个很小的修改,交换了entry中 app 和 common的顺序(对比上一个代码段):


const path = require('path');
const webpack = require('webpack');
 
module.exports = {
 entry: {
  app: './src/index.js',
  common: ['lodash']
 },
 output: {
  filename: '[name].[chunkhash].js',
  path: path.resolve(__dirname, 'dist')
 },
 plugins: [
  new CleanWebpackPlugin(['dist']),
  new webpack.optimize.CommonsChunkPlugin({
   name: 'common' // 指代index.js引入的lodash库
  }),
  new webpack.optimize.CommonsChunkPlugin({
   name: 'manifest' // 用于提取manifest
  })
 ]
}

打包后:

这里发现对比上一张图片发现,common的hash值又发生改变了!!而且根本没有更改index.js的内容app的hash也变了,只是换了一下顺序而已!

大家注意看本张图与上一张图的模块解析顺序([1],[2],[3]...之后所对应的模块)。发现上一张图,lodash第一个解析,而现在lodash最后一个解析。

这就是hash更变的原因:这是因为每个module.id 会基于默认的解析顺序(resolve order)进行增量。也就是说,当解析顺序发生变化,ID 也会随之改变,所以hash值也会发生变化。

有人可能会决定,一般我们都不会更换webpack.config.js中entry的入口顺序,那么是否我就不会遇见这个问题了。答案是否定的,除否你能保证资源文件都写在entry的顶部。否则会出现这样的情况:

假如entry的顺序为: app -> common, 那么解析顺序为 index.js → lodash。 如果之后index.js引入了 print.js,那么解析顺序变为 index.js → print.js -> lodash。

以上,我们并没有在entry中更改入口顺序,解析的顺序还是会发生改变,common的hash还是会发生,不能缓存。

这里我们就引入一个新的组件:HashedModuleIdsPlugin:根据hash生成ID(NamedModulesPlugin也具有同样的效果,但是是根据路径名生成ID,可读性更高,也由此编译时间会相对长一些)。 这样module.id就不会使用数字标识符,而使用hash:


const path = require('path');
const webpack = require('webpack');
 
module.exports = {
 entry: {
  common: ['lodash'],
  app: './src/index.js'
 },
 output: {
  filename: '[name].[chunkhash].js',
  path: path.resolve(__dirname, 'dist')
 },
 plugins: [
  new CleanWebpackPlugin(['dist']),
  new webpack.HashedModuleIdsPlugin(), // 引入该插件
  new webpack.optimize.CommonsChunkPlugin({
   name: 'common' // 指代index.js引入的lodash库
  }),
  new webpack.optimize.CommonsChunkPlugin({
   name: 'manifest' // 用于提取manifest
  })
 ]
}

打包发现,之前[ ]里都是数字,现在都是一些字符,

接下来,我们再把app和common的顺序调换一下,并且随意修改index.js,再次打包:

现在大功告成,common的hash没有改变,而因为更变了内容app的hash改变了,这正是我们想要的结果。

위 내용은 웹팩 캐싱 및 독립 패키징 사용에 대해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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