공급 업체 스크립트를 개별적으로 번들로 묶고 Webpack과 함께 필요에 따라 필요한 방법은 무엇입니까?


173

나는 가능하다고 생각되는 것을하려고 노력하고 있지만 실제로는 웹 팩 문서에서 어떻게 해야하는지 이해할 수 없습니다.

서로 의존 할 수도 있고 그렇지 않을 수도있는 여러 모듈로 JavaScript 라이브러리를 작성 중입니다. 또한 jQuery는 모든 모듈에서 사용되며 일부 모듈에는 jQuery 플러그인이 필요할 수 있습니다. 이 라이브러리는 여러 다른 웹 사이트에서 사용되며 일부 또는 모든 모듈이 필요할 수 있습니다.

내 모듈 간의 종속성을 정의하는 것은 매우 쉽지만 타사 종속성을 정의하는 것이 예상보다 어렵습니다.

내가 달성하고자하는 것 : 각 응용 프로그램마다 필요한 타사 종속성이있는 번들 파일과 라이브러리의 필요한 모듈이있는 두 개의 번들 파일을 원합니다.

: 내 라이브러리에 다음 모듈이 있다고 상상해 봅시다.

  • a (필수 : jquery, jquery.plugin1)
  • b (필수 : jquery, a)
  • c (필수 : jquery, jquery.ui, a, b)
  • d (필수 : jquery, jquery.plugin2, a)

그리고 모듈 a, b 및 c가 필요한 앱이 있습니다 (고유 항목 파일로 참조하십시오). 이 경우 웹팩은 다음 파일을 생성해야합니다.

  • 공급 업체 번들 : jquery, jquery.plugin1 및 jquery.ui 사용;
  • 웹 사이트 번들 : 모듈 a, b 및 c;

결국 jQuery를 전역으로 사용하기를 원하므로 모든 단일 파일에서 필요하지 않습니다 (예 : 기본 파일에서만 필요). 그리고 jQuery 플러그인은 필요한 경우 $ 전역을 확장합니다 (필요하지 않은 다른 모듈에서 사용할 수 있다면 문제가되지 않습니다).

이것이 가능하다고 가정하면이 경우 웹팩 구성 파일의 예는 무엇입니까? 구성 파일에서 로더, 외부 장치 및 플러그인의 여러 조합을 시도했지만 실제로 수행중인 작업과 사용해야하는 것을 얻지 못했습니다. 감사합니다!


2
당신의 해결책은 무엇입니까? 괜찮은 접근 방식을 찾았습니까? 그렇다면 게시하십시오! 감사합니다
GeekOnGadgets

답변:


140

내 webpack.config.js (버전 1,2,3) 파일에서

function isExternal(module) {
  var context = module.context;

  if (typeof context !== 'string') {
    return false;
  }

  return context.indexOf('node_modules') !== -1;
}

내 플러그인 배열에서

plugins: [
  new CommonsChunkPlugin({
    name: 'vendors',
    minChunks: function(module) {
      return isExternal(module);
    }
  }),
  // Other plugins
]

이제 필요에 따라 타사 라이브러리를 하나의 파일에만 추가하는 파일이 있습니다.

공급 업체와 진입 점 파일을 분리하는 위치를 더 세분화하려면 다음을 수행하십시오.

plugins: [
  new CommonsChunkPlugin({
    name: 'common',
    minChunks: function(module, count) {
      return !isExternal(module) && count >= 2; // adjustable
    }
  }),
  new CommonsChunkPlugin({
    name: 'vendors',
    chunks: ['common'],
    // or if you have an key value object for your entries
    // chunks: Object.keys(entry).concat('common')
    minChunks: function(module) {
      return isExternal(module);
    }
  })
]

플러그인 순서는 매우 중요합니다.

또한 이것은 버전 4에서 변경 될 예정입니다. 공식적인 경우이 답변을 업데이트합니다.

업데이트 : Windows 사용자를위한 indexOf 검색 변경


1
내 질문을 게시했을 때 이것이 이미 가능한지 모르겠지만 이것이 실제로 내가 찾던 것입니다. 이 솔루션을 사용하면 더 이상 공급 업체 항목 청크를 지정할 필요가 없습니다. 고마워요!
bensampaio

1
isExternalminChunks내 하루 를 만들었습니다. 이것은 어떻게 문서화되지 않습니까? 단점이 있습니까?
Wesley Schleumer de Góes

Thx, 그러나 Windows 경로에 대해 userRequest.indexOf ( '/ node_modules /')를 userRequest.indexOf ( 'node_modules')로 변경
Kinjeiro

@ WesleySchleumerdeGóes는 문서화되었지만 예를 들어 options.minChunks (number|Infinity|function(module, count) -> boolean):아직 단점을 보지 못했습니다.
Rafael De Leon

2
로더의 경로도 있고 module.userRequest로더는 아마도 경로에 있기 때문에 로더를 사용할 때는 작동하지 않습니다 node_modules. 내 코드 isExternal():return typeof module.userRequest === 'string' && !!module.userRequest.split('!').pop().match(/(node_modules|bower_components|libraries)/);
cdauth

54

문제를 완전히 이해했는지 잘 모르겠지만 최근에 비슷한 문제가 발생했기 때문에 도와 드리겠습니다.

공급 업체 번들.

이를 위해 CommonsChunkPlugin 을 사용해야 합니다. 구성에서 청크 이름 (예 :) vendor과 생성 될 파일 이름 ( vendor.js)을 지정합니다.

new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js", Infinity),

이제 중요한 부분은 vendor라이브러리의 의미를 지정해야 하며 항목 섹션에서이를 수행하는 것입니다. 새로 선언 된 청크의 이름과 같은 이름을 가진 항목 목록에 항목이 하나 더 있습니다 (이 경우 '공급 업체'). 해당 항목의 값은 vendor번들 로 이동하려는 모든 모듈의 목록이어야합니다 . 귀하의 경우 다음과 같이 보일 것입니다 :

entry: {
    app: 'entry.js',
    vendor: ['jquery', 'jquery.plugin1']
}

글로벌 JQuery

같은 문제가 있었고 ProvidePlugin으로 해결했습니다 . 여기서는 전역 객체를 정의하지 않고 모듈에 대한 일종의 셔트 컷을 정의합니다. 즉, 다음과 같이 구성 할 수 있습니다.

new webpack.ProvidePlugin({
    $: "jquery"
})

이제 $코드의 어느 곳에서나 사용할 수 있습니다. 웹팩은 자동으로

require('jquery')

도움이 되었기를 바랍니다. 여기에 있는 내 웹 팩 구성 파일을 볼 수도 있습니다

나는 webpack을 좋아하지만 문서가 세상에서 가장 좋은 것은 아니지만 동의합니다.하지만 사람들은 처음에 Angular 문서에 대해 같은 것을 말하고 있습니다 :)


편집하다:

진입 점 특정 벤더 청크를 사용하려면 CommonsChunkPlugins를 여러 번 사용하십시오.

new webpack.optimize.CommonsChunkPlugin("vendor-page1", "vendor-page1.js", Infinity),
new webpack.optimize.CommonsChunkPlugin("vendor-page2", "vendor-page2.js", Infinity),

그런 다음 다른 파일에 대해 다른 외부 라이브러리를 선언하십시오.

entry: {
    page1: ['entry.js'],
    page2: ['entry2.js'],
    "vendor-page1": [
        'lodash'
    ],
    "vendor-page2": [
        'jquery'
    ]
},

일부 라이브러리가 진입 점간에 겹치고 (그리고 대부분의 경우) 다른 구성을 가진 동일한 플러그인을 사용하여 공통 파일로 추출 할 수 있습니다. 예를 참조하십시오 .


답장을 보내 주셔서 감사합니다. 이것은 지금까지 내가 본 최고의 접근 방식이지만 불행히도 여전히 문제를 해결하지 못합니다 ... 예를 테스트했지만 vendor.js 파일에는 'jquery'및 'jquery.plugin1'의 모든 코드가 포함되어 있습니다. 그들은 내 모듈 중 어느 것도 필요하지 않습니다. 결국에는 항상 브라우저에로드됩니다. jquery 플러그인이 많이 있으면 절반 만 사용하더라도 파일이 매우 커집니다. 필요한 경우에만 'jquery.plugin1'을 공급 업체 번들에 포함시킬 방법이 없습니까?
bensampaio

고마워, 그래서 나는 또한 무언가를 배웠다 :) 나는 여러 공급 업체 청크를 만들어 내 대답을 업데이트했다. 어쩌면 지금은 당신에게 더 잘 맞을 것입니다.
Michał Margiel

4
이 솔루션의 문제점은 각 페이지의 종속성이 무엇인지 알고 있다고 가정한다는 것입니다. 그러나 나는 예측할 수 없다 ... jQuery는 페이지에 사용 된 모듈 중 하나에 필요한 경우 공급 업체 번들에만 포함되어야합니다. 구성 파일에서 지정하면 페이지에 사용 된 모듈에 필요하지 않더라도 항상 공급 업체 번들에있게됩니다. 기본적으로 공급 업체 번들의 내용을 예측할 수 없습니다. 그렇지 않으면 수백 페이지가있는 페이지가 두 개가 아니기 때문에 문제가 발생합니다. 문제가 있습니까? 어떤 아이디어? :)
bensampaio

나는 당신이 말하는 것을 이해하지만 문제로 보지 못합니다. 페이지에서 새 라이브러리를 사용하는 경우 해당 페이지의 공급 업체 라이브러리 목록에 추가하십시오. 문자가 거의 없습니다. 어쨌든 솔루션에서 로더를 지정하여 수행해야합니다. 새로 생성 된 모듈을 사용할 페이지를 모르는 경우 CommonChuncks 플러그인이 모듈에서 공통 라이브러리를 자동으로 추출하도록하십시오.
Michał Margiel

공급 업체 파일에 대해 별도로 컨텍스트를 설정하려면 어떻게해야합니까?
harshes53

44

스크립트를 공급 업체 스크립트와 별도로 자동 번들링하는 데 관심이있는 경우 :

var webpack = require('webpack'),
    pkg     = require('./package.json'),  //loads npm config file
    html    = require('html-webpack-plugin');

module.exports = {
  context : __dirname + '/app',
  entry   : {
    app     : __dirname + '/app/index.js',
    vendor  : Object.keys(pkg.dependencies) //get npm vendors deps from config
  },
  output  : {
    path      : __dirname + '/dist',
    filename  : 'app.min-[hash:6].js'
  },
  plugins: [
    //Finally add this line to bundle the vendor code separately
    new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.min-[hash:6].js'),
    new html({template : __dirname + '/app/index.html'})
  ]
};

이 기능에 대한 자세한 내용은 공식 문서를 참조하십시오 .


4
vendor : Object.keys(pkg.dependencies) 항상 작동 하는 것은 아니며 패키지 제작 방법에 따라 다릅니다.
markyph

1
항상 package.json설정 방법에 따라 다릅니다 . 이 해결 방법은 대부분의 경우 작동하지만 다른 경로를 사용해야하는 예외가 있습니다. 커뮤니티에 도움을주기 위해 질문에 대한 답변을 게시하는 것이 흥미로울 수 있습니다.
Freezystem

16
나는 이것을 좋아한다. 조금 오줌 싸게했다.
cgatian

3
그것도 당신도 인해 ... 코드에서 전혀 사용되지 않는 수 있음을 패키지에 포함되므로주의 Object.keys(pkg.dependencies)모든 번들됩니다 !!!! 거기에 많은 로더가 나열되어 있다고 가정 해 봅시다 ... 그렇습니다. 그래서 조심하십시오 ... 신중하게 devDependency는 무엇이고 의존은 무엇입니까
Rafael Milewski

1
@RafaelMilewski 왜 로더가 dependencies있습니까?
바지

13

또한 귀하의 사례를 완전히 이해했는지 확실하지 않지만 다음은 각 번들에 대해 별도의 공급 업체 청크를 생성하는 구성 스 니펫입니다.

entry: {
  bundle1: './build/bundles/bundle1.js',
  bundle2: './build/bundles/bundle2.js',
  'vendor-bundle1': [
    'react',
    'react-router'
  ],
  'vendor-bundle2': [
    'react',
    'react-router',
    'flummox',
    'immutable'
  ]
},

plugins: [
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor-bundle1',
    chunks: ['bundle1'],
    filename: 'vendor-bundle1.js',
    minChunks: Infinity
  }),
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor-bundle2',
    chunks: ['bundle2'],
    filename: 'vendor-bundle2-whatever.js',
    minChunks: Infinity
  }),
]

CommonsChunkPlugin문서에 연결 하십시오 : http://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin


이 솔루션의 문제는 Michal이 제공 한 문제와 동일하다고 생각합니다. 당신은 bundle1과 bundle2에 대한 벤더 의존성을 알고 있다고 가정하지만, 그렇지 않습니다 ... 200 개의 번들이 구성 파일에 모든 것을 지정하고 싶다고 상상하십니까? 예제 react를 사용할 때 bundle1 및 bundl2에 명시 적으로 필요한 경우 공급 업체 번들에만 있어야합니다. 구성 파일에서 지정하지 않아도됩니다 ... 이것이 의미가 있습니까? 어떤 아이디어?
bensampaio

@Anakin 문제는 200 개의 공급 업체 도구를 별도의 파일로 묶으려는 이유입니다. 공통 도구를 별도의 파일로 묶고 나머지는 프로젝트 번들과 함께 유지합니다.
maxisam

@Anakin 나는 같은 문제를 다루고 있다고 생각합니다. 잘못되면 수정 하시겠습니까? stackoverflow.com/questions/35944067/…
pjdicke
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.