Skip to content

Webpack2와 모듈번들링을 위한 초보자 가이드

Kwan-Ung Park edited this page Jun 18, 2017 · 12 revisions

https://www.sitepoint.com/beginners-guide-to-webpack-2-and-module-bundling/?utm_source=frontendfocus&utm_medium=email 를 번역한 글입니다.

Webpack 은 모듈 번들러 입니다.

모던 웹 개발에 있어서 Webpack은 매우 중요한 도구중에 하나로 자리 잡았습니다. 주로 자바스크립트를 위한 모듈 번들러이지만, HTML, CSS 심지어 이미지들 같은 프론트엔드 assets 들을 변환시켜 주는 법을 배울 수 있습니다. 여러분의 앱에 HTTP 요청 갯수를 컨트롤 할 수 있게 만들 수 있으며, 다른 종류의 assets(Jade, Sass, ES6등)를 사용 할 수 있게 도와줍니다. 또한 Webpack을 사용하면 npm 패키지를 쉽게 사용할 수 있습니다.

이번 포스팅은 webpack을 처음 사용하는 사람을 대상으로 하며, 초기 설치, configuration, modules, loaders, plugins, code splitting, hot module replacement에 대해 설명합니다. 만약 여러분이 비디오 튜토리얼이 좋다면, Glen Maddern’s의 Webpack from First Principles을 시작점으로 삼아 webpack의 특별한 점을 이해하는 것이 좋을것 같습니다.
이제부터 집에서 따라가기 위해 NodeJS 설치해야하며, 또한 Github 저장소에서 데모앱을 다운 받을 수 있습니다.

Setup

이제 npm으로 새로운 프로젝트를 초기화하고, webpack을 설치합시다.

mkdir webpack-demo
cd webpack-demo
npm init -y
npm install webpack@beta --save-dev
mkdir src
touch index.html src/app.js webpack.config.js
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>hello webpack</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="dist/bundle.js"></script>
  </body>
</html>
// src/app.js
const root = document.querySelector('#root');
root.innerHTML = `<p>Hello webpack</p>`;
// webpack.config.js

const webpack = require('webpack')
const path = require('path')

const extractCommons = new webpack.optimize.CommonsChunkPlugin({
  name: 'commons',
  filename: 'common.js'
})

const ExtractTextPlugin = require('extract-text-webpack-plugin')
const extractCSS = new ExtractTextPlugin('[name].bundle.css')
const config = {
  context: path.resolve(__dirname, 'src'),
  entry: './app.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  module: {
    rules: [{
      test: /\.js$/,
      include: path.resolve(__dirname, 'src'),
      use: [{
        loader: 'babel-loader',
        options: {
          presets: [
            ['es2015', {modules: false}]
          ]
        }
      }]
    }]
  }
}

module.exports = config

위 설정은 webpack에게 entry pointsrc/app.js로 하고, output/dist/bundle.js로 하라고 지시하고, 바벨을 이용하여 모든 .js 파일들을 ES2015 에서 ES5 로 변환 하라고 하는 흔한 방식입니다.
위 작업을 진행 하기 위해 babel-core, webpack loader 인 babel-loader, 그리고 babel-preset-es2015 3개의 패키지를 설치하여야 합니다. { modules: false }Tree Shaking 사용하여, bundle로 부터 나온 사용하지 않는 것들을 삭제하여 파일 크기를 줄입니다.

npm install babel-core babel-loader babel-preset-es2015 --save-dev

마지막으로 package.json 파일에 scripts 부분을 다음과 같이 교체합니다.

"scripts": {
  "start": "webpack --watch",
  "build": "webpack -p"
},

커맨드라인에서 npm start 를 실행하면, webpack은 watch 모드로 실행 될 것이며, src 디렉토리에 .js 파일들이 변경되면, 번들파일이 다시 컴파일 됩니다. 콘솔 결과는 번들 생성 정보를 알려주며, 결과로 나온 번들의 갯수와 사이즈에 대해 주의깊게 살펴봐야 합니다.

webpack result

이제 당신은 브라우저에서 index.html 을 실행 할 수 있으며, Hello webpack 을 볼 수 있을겁니다.

open index.html

dist/bundle.js 파일을 열어 webpack이 한 일을 보면, 맨위에 webpack 모듈 부트스트래핑 코드와 오른쪽 맨 아래는 우리의 모듈을 볼 수 있습니다. 아직까진 인상깊진 않겠지만, 여러분은 ES6모듈을 사용하여 개발 할 수 있고, webpack이 모든 브라우저에서 실행 할 수 있는 번들을 생성시켜 줄 것 입니다.
Ctrl+C로 webpack을 멈추고, 프로덕션 모드에서 번들을 컴파일 하기 위해 npm run build를 실행해 보겠습니다.
번들 사이즈가 2.61KB 에서 585bytes 로 줄어든 것을 볼 수 있습니다.
dist/bundle.js 를 다시 한번 보면, 복잡하고 이상한 코드를 보게 됩니다. 번들파일은 UglifyJS를 사용하여 축소되어, 코드 실행은 정확히 동일하지만, 적은 문자를 이용하여 완료되어집니다.

Modules

webpack은 다양한 포맷의 자바스크립트 모듈을 사용하는 방법을 알고 있으며, 가장 주목 할만한 2가지는 다음과 같습니다.

  • ES2015 import 구문
  • CommonJS require() 구문

우리는 lodash를 설치하고 app.js로 import 하여 위에 것을 테스트 할 수 있습니다.

npm install lodash --save
// src/app.js
import {groupBy} from 'lodash/collection'

const people = [{
  manager: 'Jen',
  name: 'Bob'
},{
  manager: 'Jen',
  name: 'Sue'
},{
  manager: 'Bob',
  name: 'Shirley'
},{
  manager: 'Bob',
  name: 'Terrence'
}]
const managerGroups = groupBy(people, 'manager')

const root = document.querySelector('#root')
root.innerHTML = `<pre>${JSON.stringify(managerGroups,null,2)}</pre>`

npm start 실행하여 webpack을 시작하고, index.html 을 새로고침합니다. 당신은 manager 에 의해 그룹화된 people 배열을 볼 수 있습니다.

people.js 모듈로 people 배열을 이동하도록 하겠습니다.

// src/people.js
const people = [{
  manager: 'Jen',
  name: 'Bob'
}, {
  manager: 'Jen',
  name: 'Sue'
}, {
  manager: 'Bob',
  name: 'Shirley'
}, {
  manager: 'Bob',
  name: 'Terrence'
}]

export default people

상대 경로로 app.js 로 부터 위 파일을 간단히 import 할 수 있습니다.

// src/app.js
import {groupBy} from 'lodash/collection'
import people from './people'

const managerGroups = groupBy(people, 'manager')

const root = document.querySelector('#root')
root.innerHTML = `<pre>${JSON.stringify(managerGroups,null,2)}</pre>`

참고 : lodash/collection 같이 상대경로 없는 import는 npm으로 인스톨된 /node_modules 에 있는 모듈입니다. 여러분 자신의 모듈은 항상 ./people 와 같은 상대경로가 필요합니다.

Loaders

우리는 babel-loader에 대해 이미 소개한적이 있습니다. babel-loader는 여러 다양한 타입 파일을 import 할 때 webpack에 어떤 작업을 할 것인지 설정할 수 있는 많은 loaders중 하나입니다. loaders를 일련의 변형으로 묶을 수 있으며, 자바스크립트에서 Sass 가 어떻게 가져오는지 작동법을 알 수 있는 좋은 방법입니다.

Sass

이 변환을 하기 위해선 3가지 분리된 loaders와 node-sass 라이브러리를 포함시켜야 합니다.

npm install css-loader style-loader sass-loader node-sass --save-dev

.scss 파일에 대한 새로운 룰을 설정해야합니다.

// webpack.config.js
rules: [{
  test: /\.scss$/,
  use: [
    'style-loader',
    'css-loader',
    'sass-loader'
  ]
},{
  // ...
}]

참고 : 만약 webpack.config.js 안에 룰을 변경하였으면, Ctrl+C 커맨드를 실행하여 webpack 종료 후 npm start 실행하여 빌드를 재시작 해야합니다.

loaders 배열은 역순으로 처리 됩니다.

  • sass-loader Sass -> CSS 로 변환.
  • css-loader 자바스크립트 안에 CSS를 해석하고, 모든 의존성 해결.
  • style-loader CSS를 document<style> 태그에 출력합니다.

당신은 loaders가 함수 호출로써 실행 된다고 생각할 수 있습니다. 하나의 loader 출력이 다음 loader의 입력으로 주게 됩니다.

styleLoader(cssLoader(sassLoader('source')))

Sass 소스파일을 추가해봅시다.

/* src/style.scss */
$bluegrey: #2B3A42;

pre{
  padding: 20px;
  background: $bluegrey;
  color: #dedede;
  text-shadow: 0 1px 1px rgba(#000, .5);
}

이제 자바스크립트에서 위 파일을 직접적으로 require 할 수 있고, app.js 맨위에 import를 사용하여 가져올 수 있습니다.

// src/app.js
import './style.scss'

// ...

index.html을 새로고침 하면 약간의 스타일링된 상태를 볼 수 있습니다.

CSS in JS

우리는 모듈로써 자바스크립트에서 Sass파일을 가져왔습니다.

dist/bundle.js을 열어서 “pre {“ 을 검색해보겠습니다. 사실 Sass는 CSS 문자열로 컴파일되어 번들내에 모듈로 저장되어졌습니다. 자바스크립트에서 이 모듈을 가져올 때, style-loader는 문자열이 포함된 <style> 태그로 삽입 합니다.

나는 여러분이 무슨 생각하는지 알고있습니다. 왜?

여기서 이 토픽에 대해 너무 깊이 파고들진 않겠지만, 몇가지 고려해야할 이유가 있습니다.:

  • 여러분의 프로젝트에 포함하길 원하는 자바스크립트 컴포넌트는 적절히 작동하기 위해 다른 assets (HTML, CSS, 이미지, SVG)에 의존합니다. 만약 모두 함께 번들링 할 수 있으면, 쉽게 import하고 쉽게 사용 할 수 있습니다.
  • Dead code elimination: 여러분의 코드에서 더이상 자바스크립트 컴포넌트를 가져오지 않는다면, CSS 또한 더이상 가져올 수 없습니다.
  • CSS Modules: CSS의 전역 네임스페이스를 만들면 여러분의 CSS를 변경 해도 부작용이 없다라고 확신하기가 어렵습니다. CSS 모듈은 기본적으로 로컬로 만들고, 여러분의 자바스크립트에서 참조할 수 있는 고유 클래스 이름을 표시함으로써 이를 변경합니다.
  • 코드를 분할 / 번들링하는 영리한 방법으로 HTTP 요청 갯수를 줄입니다.

Images

loaders 의 마지막 예제로 url-loader로 이미지를 처리하는 법을 보겠습니다.
표준 HTML 문서에서 브라우저는 <img> 태그나 배경-이미지 속성이 있는 요소를 발견하면 이미지를 가져옵니다. webpack은 이미지 소스를 자바스크립트 내부에 문자열로 저장하여 작은 이미지같은 경우 최적화 할 수 있습니다. 이러면 미리 로드하여 브라우저는 별도의 요청으로 나중에 가져올 필요가 없습니다.

npm install file-loader url-loader --save-dev

이미지를 로드하기 위하여 룰을 추가합니다.

// webpack.config.js
rules: [{
  test: /\.(png|jpg)$/,
  use: [{
    loader: 'url-loader',
    options: { limit: 10000 } // 10k 이하 이미지는 base64 문자열로 변환
  }]
},{
  // ...
}]

Ctrl+Cnpm start 커맨드로 재빌드 재시작 해보겠습니다.

아래 커맨드로 테스트이미지를 다운로드 받겠습니다.

curl https://raw.githubusercontent.com/sitepoint-editors/webpack-demo/master/src/code.png --output src/code.png

이제 app.js 맨 위에서 이미지 소스를 가져올 수 있습니다.

// src/app.js
import codeURL from './code.png'
const img = document.createElement('img')
img.src = codeURL
img.style = "background: #2B3A42; padding: 20px"
img.width = 32
document.body.appendChild(img)

// ..

여기에는 src속성에 이미지 자체 데이터 URI를 포함하고 있습니다.

<img src="data:image/png;base64,iVBO..." style="background: #2B3A42; padding: 20px" width="32">

또한, url() 에 의해 참조되는 css-loader 이미지때문에 url-loader 통해서 CSS 에서 직접적으로 이미지를 인라인 할 수 있습니다.

/* src/style.scss */
pre {
  background: $bluegrey url('code.png') no-repeat center center / 32px 32px;
}

다음과 같이 컴파일 됩니다.

pre {
    background: #2b3a42 url("data:image/png;base64,iVBO...") no-repeat scroll center center / 32px 32px;
}

##Modules to Static Assets 여러분은 loaders가 assets 간에 의존성 트리를 어떻게 빌드하는지 알아야 합니다. 아래 이미지는 webpack 홈페이지에서 보여주는 것입니다.

webpack 구조

비록 자바스크립트가 시작지점이지만, HTML, CSS, SVG와 같은 각각 다른 asset 타입마다 빌드 프로세스의 일부분으로 간주되어야 하는 그들 자신만의 의존성을 가지고 있는점에 감사드립니다.

Plugins

우리는 이미 webpack 플러그인이 내장된 예제를 보았습니다. npm run build 스크립트를 통해 호출된 webpack -p는 webpack과 함께 제공되는 UglifyJsPlugin을 사용하여 production을 위한 번들 파일을 minify 합니다.
loaders가 하나의 파일을 변환하는 동안 플러그인은 더 큰 코드 청크 에서 작동합니다.

Common code

commons-chunk-plugin 은 webpack에서 제공하는 또다른 핵심 플러그인으로, 여러 진입점 사이에 공유되는 코드로 구성되는 별도의 모듈을 생성하는데 사용할 수 있습니다. 지금까지는 하나의 진입점과 하나의 번들을 사용하였습니다. 다중 진입과 출력 파일 분할을 통해서 많은 이득을 얻을 수 있는 실제 시나리오가 많이 있습니다.
공용 앱인 app.js와 관리영역인 admin.js와 같이 모듈을 공유하는 두가지 다른 영역의 어플리케이션을 가지고 있는 경우 다음과 같이 별도의 진입점을 생성할 수 있습니다.

// webpack.config.js
const webpack = require('webpack')
const path = require('path')

const extractCommons = new webpack.optimize.CommonsChunkPlugin({
  name: 'commons',
  filename: 'commons.js'
})

const config = {
  context: path.resolve(__dirname, 'src'),
  entry: {
    app: './app.js',
    admin: './admin.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].bundle.js'
  },
  module: {
    // ...
  },
  plugins: [
    extractCommons
  ]
}

module.exports = config

[name]이 포함된 output.filename 속성 변경을 확인 하십시오. 위 설정을 통해서 청크 네임으로 변경된 app.bundle.jsadmin.bundle.js라는 2개의 번들파일을 예상 할 수 있습니다.
commonschunk 플러그인은 진입점의 공유 모듈을 포함하는 3번째 파일인 commons.js 을 생성합니다.

// src/app.js
import './style.scss'
import {groupBy} from 'lodash/collection'
import people from './people'

const managerGroups = groupBy(people, 'manager')

const root = document.querySelector('#root')
root.innerHTML = `<pre>${JSON.stringify(managerGroups, null, 2)}</pre>`
// src/admin.js
import people from './people'

const root = document.querySelector('#root')
root.innerHTML = `<p>There are ${people.length} people.</p>`

이 진입점은 다음 파일들을 생성합니다.

  • app.bundle.js : 스타일lodash/collection 모듈을 포함
  • admin.bundle.js : 추가 모듈 미포함
  • commons.js : people 모듈 포함

이제 두 영역 모두에서 commons 청크 파일을 포함 시킬 수 있습니다.:

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Hello webpack</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="dist/commons.js"></script>
    <script src="dist/app.bundle.js"></script>
  </body>
</html>
<!-- admin.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Hello webpack</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="dist/commons.js"></script>
    <script src="dist/admin.bundle.js"></script>
  </body>
</html>

브라우저에서 index.htmladmin.html을 실행시키면 자동적으로 commons 청크 파일이 생성되어 실행되는 것을 볼 수 있습니다.

Extracting CSS

또다른 유명한 플러그인 인 extract-text-webpack-plugin은 모듈을 자체 파일로 추출 하는데 사용합니다.

아래에서는 .scss 룰을 수정하여 Sass를 컴파일하고, CSS를 불러온 후, 각 CSS 번들로 추출함으로써 자바스크립트 번들에서 삭제 합니다.

npm install extract-text-webpack-plugin@2.0.0-beta.4 --save-dev
// webpack.config.js
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const extractCSS = new ExtractTextPlugin('[name].bundle.css')

const config = {
  // ...
  module: {
    rules: [{
      test: /\.scss$/,
      loader: extractCSS.extract(['css-loader','sass-loader'])
    },{
      // ...
    }]
  },
  plugins: [
    extractCSS,
    // ...
  ]
}

webpack을 재시작하면 새로운 번들인 app.bundle.css 을 볼수 있으며, 아래와 같이 바로 링크를 삽입 할 수 있습니다.

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Hello webpack</title>
    <link rel="stylesheet" href="dist/app.bundle.css">
  </head>
  <body>
    <div id="root"></div>
    <script src="dist/commons.js"></script>
    <script src="dist/app.bundle.js"></script>
  </body>
</html>

브라우저를 새로고침하면 컴파일된 CSS는 app.bundle.js 에서 app.bundle.css 로 이동된 것을 볼수 있습니다. 성공!

Code Splitting

우리는 이미 몇몇 방법으로 코드를 나누는 것을 보았습니다.

  • 각각의 진입점을 수동으로 생성
  • commons 청크로 공유코드 자동으로 분리
  • extract-text-webpack-plugin으로 컴파일된 번들에서 청크 추출

또다른 방법으로 System.import 또는 require.ensure 을 통해 우리의 번들을 분리할 수 있습니다. 이런 함수들로 코드를 랩핑하면 런타임에 실행될 필요한 청크를 생성할 수 있습니다. 이 방식으로 하면 클라이언트에서 시작될때 모든 파일들을 전송하지 않아도 되므로 실행시간 성능에 향상시킬 수 있습니다. System.import는 인자로 모듈이름을 전달하고, Promise를 반환받습니다. require.ensure는 의존성 목록, 콜백 그리고 청크를 위한 옵션 이름을 전달합니다.

여러분 앱에 한 부분이 의존성이 많고 다른 앱 부분에는 불필요하다면, 앱 자체 번들로 나누는 것이 좋습니다. d3가 필요한 dashboard.js 이름의 새 모듈을 추가하여 위 내용을 설명하도록 하겠습니다.

npm install d3 --save
// src/dashboard.js
import * as d3 from 'd3';

console.log('Loaded!', 'd3');

export const draw = () => {
  console.log('Draw!')
}

app.js 아래에서 dashboard.js을 가져오겠습니다.

// ..
const routes = {
  dashboard: () => {
    System.import('./dashboard').then((dashboard) => {
      dashboard.draw()
    }).catch((err) => {
      console.log('Chunk loading failed')
    })
  }
}

// timeout으로 비동기 로딩 데모실행
setTimeout(routes.dashboard, 1000)

모듈을 비동기로 로드하여 추가하였기 때문에, 우리 webpack 설정에 어디에서 가져올지 알 수 있도록 적절한 output.publicPath 속성이 필요합니다.

// webpack.config.js

const config = {
  // ...
  output: {
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/dist/',
    filename: '[name].bundle.js'
  },
  // ... 
}

빌드를 재시작하면, 0.bundle.js이라는 새로운 번들 파일을 보게 될것입니다.

webpack build result

위 이미지에서 webpack이 눈에 띄게 하려고 [big] 번들에 하이라이팅하도록 한 것에 주목하시기 바랍니다.
0.bundle.js은 JSONP 요청에 의존하여 패치 되므로, 파일 시스템에서 직접 파일을 로드하면 더이상 잘라낼 수가 없습니다. 그래서 서버를 운영해야 할 필요가 생겼습니다.

python -m SimpleHTTPServer 8001

http://localhost:8001/을 열어보시기 바랍니다.

로딩 1초후에 동적으로 생성된 /dist/0.bundle.js 번들파일에 대한 GET 요청을 보게 되고, 콘솔에 Loaded! 를 확인 하실 수 있습니다. 성공!

Webpack Dev Server

Live reloading은 파일이 변경될 때 자동으로 새로고침 해줌으로써 개발 경험을 향상 시킬 수 있습니다. 간단히 설치하고 webpack-dev-server로 시작하면 됩니다.

npm install webpack-dev-server@2.2.0-rc.0 --save-dev

package.json 에서 start 스크립트를 수정하겠습니다.

"start": "webpack-dev-server --inline",

npm start 로 서버를 시작하면 여러분의 브라우저에서 http://localhost:8080/를 열 수 있습니다.
src 폴더에 people.js 의 이름을 바꿔보던가, style.scss 안에 스타일을 바꿔보면, 여러분의 눈으로 화면에서 변화되는 것을 보게 됩니다.

Hot Module Replacement

만약 여러분이 live reloading에 감탄했다면, hot module replacement(HMR) 에 더 놀랄것입니다.

2017년에, 전역 상태의 싱글페이지앱에서 이미 경험해보았습니다. 개발하는 동안 컴포넌트를 작게 변경 할 것이며, 출력사항을 볼 수 있는 실제 브라우저에서 변화된 내용이 반영 됬는지 확인 할 수 있습니다. 수동으로 페이지를 새로고침하거나, live reload 하면 전체 상태가 날라가버리고, 처음부터 다시 시작 해야 합니다. Hot module replacement는 영원히 바뀌어 있을 것입니다.

개발자 워크플로우에서 개발자가 모듈을 변경 하게 되면 브라우저는 새로고침(로컬 상태를 날려버리거나)하거나 다른 모듈을 건들지 않고 런타임에 모듈을 컴파일하고 스왑하게 됩니다. 여전히 수동으로 새로고침이 필요하지만, HMR 은 많은 양의 시간을 절약할 수 있으며 미래적인 느낌을 받을 수 있습니다.

package.jsonstart 스크립트를 수정하겠습니다.

"start": "webpack-dev-server --inline --hot",

app.js 맨 위에 의존적인 다른 것을 포함하여 모든 모듈들을 webpack이 hot reloading을 하게끔 허락한다고 작성합니다.

if(module.hot){
  module.hot.accept()
}
// ... 

참고: webpack-dev-server --hotmodule.hottrue로 세팅하며, 개발모드에서만 사용됩니다. 프로덕션 모드로 빌드 할 경우 module.hotfalse로 세팅되고 번들에서 제거됩니다.

webpack.config.js의 플러그인 목록에 NamedModulesPluign을 추가하면 더 나은 콘솔로깅으로 향상 시킬 수 있습니다.

plugins: [
  new webpack.NamedModulesPluign(),
  // ...
]

마지막으로 <input> 요소를 페이지에 추가하고, 요소에 텍스트를 입력해놓고 다른 모듈을 변경했을 때 전체 페이지 새로고침이 발생하지 않는 것을 확인 할 수 있습니다.

<body>
  <input />
  <div id="root"></div>
  ...

npm start 로 서버를 재시작하고 hot reloading을 봐보세요!

people.js 에 이름을 변경하고, input 요소에 HMR Rules를 입력하면 페이지 새로고침 없이 스왑되고, input 상태를 유지 하고 있는 것을 확인 할 수 있습니다.

지금까지 간단한 예제였는데, 얼마나 유용한지 알 수 있기를 바랍니다. React 같은 컴포넌트 기반 개발에서는 특히 상태와 분리된 많은 dumb 컴포넌트가 있고, 컴포넌트 상태를 잃지 않고 스왑하고 다시 렌더링 할 수 있으므로, 즉각적인 피드백을 얻을 수 있습니다.

##Hot Reloading CSS

style.scss<pre> 요소의 백그라운드 색깔을 변경하고 보면 HMR로 교체되지 않는것 을 보게 됩니다.

pre {
  background: red;
}

style-loader를 사용할 때 HMR이 자유롭게 사용 할 수 있도록 제공된다고 합니다. 그래서 다른 작업을 할 필요가 없습니다. 교체 할 수 없는 외부 CSS파일로 CSS 모듈을 추출 하여 연결된 링크를 끊었습니다.
SASS 룰을 원래대로 돌리고, 플러그인 목록에서 extractCSS 을 삭제하면 SASS 또한 hot reloading을 할 수 있습니다.

{
  test: /\.scss$/,
  loader: ['style-loader', 'css-loader','sass-loader']
}

HTTP/2

webpack과 같은 모듈 번들러를 사용하면 얻는 이점 중 하나는 assets을 빌드하고 클라이언트에서 패치하는 방법을 제어할 수 있으므로 성능을 향상시키는데 도움이 된다는 것 입니다. 클라이언트에서 만들어진 것들에 대한 요청 수를 줄이기 위해 파일을 연결하는 것이 수년동안 best practice로 간주되고 있었습니다. 이는 여전히 유효하지만, HTTP/2 에서는 단일 요청으로 다중 파일을 전달할 수 있게 되어 더이상의 silver bullet 이 아니게 되었습니다. 앱은 실제로 많은 작은 파일들을 개개인별로 캐싱하여 이점을 얻을 수 있습니다. 그래서 클라이언트는 전체 번들을 다시 가져오는 대신 변경된 모듈 부분에 대해서만 가져올 수 있습니다.

Webpack 창시자인 Tobias KoppersHTTP/2에서도 여전히 번들링이 중요하다는 내용에 대해 포스팅을 해논게 있습니다.

자세한 내용은 webpack & HTTP/2을 읽어보세요.

Over to You

webpack2에 도움이 될 소개글을 찾았고, 많은 도움을 내기 위해 webpack을 사용 할 수 있기를 바랍니다. webpack의 설정, 로더 그리고 플러그인에 대해 골머리를 썩겠지만, 이 도구들을 배우면 효과가 있을 것입니다.

아직 문서는 작성중이지만, 기존 Webpack1 프로젝트를 새롭게 바꾸려면 v1 -> v2 로 쉽게 마이그레이션 할 수 있는 가이드를 참고하세요.

위키

기술 문서
Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.