To v2 or v3 from v1
- ë¤ì ì¹ì ììë webpack 1ìì 2ë¡ì 주ì ë³ê²½ ì¬íì ì¤ëª í©ëë¤.
resolve.root, resolve.fallback, resolve.modulesDirectories
ì ìµì
ë¤ì resolve.modules ë¡ ëì²´ëììµëë¤. ìì¸í ì¬ì©ë²ì resolvingì ì°¸ê³ íì¸ì.
resolve: {
- root: path.join(__dirname, "src")
+ modules: [
+ path.join(__dirname, "src"),
+ "node_modules"
+ ]
}resolve.extensions
ì´ ìµì
ì ë ì´ì ë¹ ë¬¸ìì´ì ì ë¬í íìê° ììµëë¤. ì´ ëìì resolve.enforceExtensionì¼ë¡ ì´ëëììµëë¤. ìì¸í ì¬ì©ë²ì resolving 를 ì°¸ê³ íì¸ì.
resolve.*
ì¬ê¸°ìì ì¬ë¬ APIê° ë³ê²½ëììµëë¤. íí ì¬ì©ëì§ ìì¼ë¯ë¡ ìì¸í ëì´íì§ ììµëë¤. ìì¸í ë´ì©ì resolvingì ì°¸ê³ íì¸ì.
module.loaders is now module.rules
ì´ì ì ë¡ëì¤ì ì ë¡ëì ê·¸ ì´ìì ì¤ì ì´ íê°ëë ê°ë ¥í ê·ì¹ ìì¤í
ì¼ë¡ ëì²´ ëììµëë¤.
í¸íì±ì ìí´ ì´ì ì module.loaders 구문ì ì¬ì í ì í¨íë©° ì´ì ì´ë¦ì 구문 ë¶ìë©ëë¤.
ë¤ì´ë° 컨벤ì
ë¤ì´ ì´í´í기 ì¬ìì¡ê³ module.rules를 ì¬ì©íëë¡ ì¤ì ì ì
ê·¸ë ì´ë í´ì¼íë ì¢ì ì´ì ì
ëë¤.
module: {
- loaders: [
+ rules: [
{
test: /\.css$/,
- loaders: [
- "style-loader",
- "css-loader?modules=true"
+ use: [
+ {
+ loader: "style-loader"
+ },
+ {
+ loader: "css-loader",
+ options: {
+ modules: true
+ }
+ }
]
},
{
test: /\.jsx$/,
loader: "babel-loader", // Do not use "use" here
options: {
// ...
}
}
]
}Chaining loaders
webpack 1ììì ê°ì´ ë¡ë를 ì°ê²°íì¬ ë¡ëìì ë¡ëë¡ ê²°ê³¼ë¥¼ ì ë¬í ì ììµëë¤.
rule.use 를 ì¬ì©íì¬, use 를 ë¡ë ë°°ì´ë¡ ì¤ì í ì ììµëë¤.
webpack 1ìì ë¡ëë ì¼ë°ì ì¼ë¡ !ë¡ ì°ê²°ëììµëë¤. ì´ ì¤íì¼ì ë ê±°ì ìµì
module.loaders 를 ì¬ì©íë ê²½ì°ìë§ ì§ìë©ëë¤.
module: {
- loaders: [{
+ rules: [{
test: /\.less$/,
- loader: "style-loader!css-loader!less-loader"
+ use: [
+ "style-loader",
+ "css-loader",
+ "less-loader"
+ ]
}]
}Automatic -loader module name extension removed
ë¡ë를 ì°¸ê³ í ë -loader íì¥ì를 ë ì´ì ìëµí ì ììµëë¤.
module: {
rules: [
{
use: [
- "style",
+ "style-loader",
- "css",
+ "css-loader",
- "less",
+ "less-loader",
]
}
]
}resolveLoader.moduleExtensions ì¤ì ìµì
ì ì¬ì©íì¬ ì´ì ëìì ê³ì ì íí ì ìì§ë§ ì´ë ê¶ì¥ëì§ ììµëë¤.
+ resolveLoader: {
+ moduleExtensions: ["-loader"]
+ }ì´ ë³ê²½ ì´ì ë #2986 ì ì°¸ê³ íì¸ì.
json-loader is not required anymore
JSON íì¼ì ëí´ ì¤ì ë ë¡ëê° ìì¼ë©´, webpackì ìëì¼ë¡ json-loaderë¡ JSON íì¼ì ë¡ëíë ¤ê³ ìëí©ëë¤.
module: {
rules: [
- {
- test: /\.json/,
- loader: "json-loader"
- }
]
}webpack, node.js ë° browserify ê°ì í경차ì´ë¥¼ ìì 기 ìí´ ê·¸ë ê² íê¸°ë¡ ê²°ì íìµëë¤.
Loaders in configuration resolve relative to context
webpack 1 ìì, ì¤ì ë ë¡ëê° ì¼ì¹íë íì¼ì 기ì¤ì¼ë¡ íì¸ëì´ì§ëë¤. íì§ë§, webpack 2 ììë, ì¤ì ë ë¡ëë context ìµì
ì 기ì¤ì¼ë¡ íì¸ë©ëë¤.
ì´ê²ì npm link 를 ì¬ì©íê±°ë ì¸ë¶ context 모ëì ì°¸ê³ í ë ë¡ëì ìí´ ë°ìíë ì¤ë³µ 모ë 문ì 를 í´ê²°í©ëë¤.
ì´ ë¬¸ì 를 í´ê²°í기 ìí´ ëª ê°ì§ íµì ì ê±°í ì ììµëë¤.
module: {
rules: [
{
// ...
- loader: require.resolve("my-loader")
+ loader: "my-loader"
}
]
},
resolveLoader: {
- root: path.resolve(__dirname, "node_modules")
}module.preLoaders and module.postLoaders were removed:
module: {
- preLoaders: [
+ rules: [
{
test: /\.js$/,
+ enforce: "pre",
loader: "eslint-loader"
}
]
}UglifyJsPlugin sourceMap
UglifyJsPlugin ì sourceMap ìµì
ì true ëì false ë¡ ê¸°ë³¸ ì¤ì ë©ëë¤. ì¦, ìµìíë ì½ëì ìì¤ë§µì ì¬ì©íê±°ë uglifyjs ê²½ê³ ì ëí ì¬ë°ë¥¸ ì¤ ë²í¸ë¥¼ ìíë ê²½ì° UglifyJsPluginìì sourceMap: true를 ì¤ì í´ì¼ í©ëë¤.
devtool: "source-map",
plugins: [
new UglifyJsPlugin({
+ sourceMap: true
})
]UglifyJsPlugin warnings
UglifyJsPluginì compress.warnings ìµì
ì ì´ì true ëì falseë¡ ê¸°ë³¸ ì¤ì ë©ëë¤.
ì¦, uglifyjs ê²½ê³ ë¥¼ ë³´ë ¤ë©´ compress.warnings를 trueë¡ ì¤ì í´ì¼ í©ëë¤.
devtool: "source-map",
plugins: [
new UglifyJsPlugin({
+ compress: {
+ warnings: true
+ }
})
]UglifyJsPlugin minimize loaders
UglifyJsPlugin ì ë ì´ì ë¡ë를 ìµìí 모ëë¡ ì ííì§ ììµëë¤. minimize: true ì¤ì ì ì¥ê¸°ì ì¼ë¡ ë¡ë ìµì
ì íµí´ ì ë¬ëì´ì¼ í©ëë¤. ê´ë ¨ ìµì
ì ë¡ë 문ì를 ì°¸ê³ íì¸ì.
ë¡ëì ìµìí 모ëë webpack 3 ì´ììì ì ê±°ë©ëë¤.
ì´ì ë¡ëìì í¸íì±ì ì ì§í기 ìí´ íë¬ê·¸ì¸ì íµí´ ë¡ë를 ìµìí 모ëë¡ ì íí ì ììµëë¤.
plugins: [
+ new webpack.LoaderOptionsPlugin({
+ minimize: true
+ })
]DedupePlugin has been removed
webpack.optimize.DedupePluginì ë ì´ì íìíì§ ììµëë¤. ì¤ì ìì ì ê±°íì¸ì.
BannerPlugin - breaking change
BannerPluginì ë ì´ì ë ê°ì 매ê°ë³ì를 íì©íì§ ìê³ ë¨ì¼ ìµì
ê°ì²´ë¥¼ íì©í©ëë¤.
plugins: [
- new webpack.BannerPlugin('Banner', {raw: true, entryOnly: true});
+ new webpack.BannerPlugin({banner: 'Banner', raw: true, entryOnly: true});
]OccurrenceOrderPlugin is now on by default
OccurrenceOrderPluginì ì´ì 기본ì ì¼ë¡ íì±íëë©° ì´ë¦ì´ ë³ê²½ëììµëë¤(webpack 1ì OccurenceOrderPlugin).
ë°ë¼ì ì¤ì ìì íë¬ê·¸ì¸ì ì ê±°í´ì¼ í©ëë¤.
plugins: [
// webpack 1
- new webpack.optimize.OccurenceOrderPlugin()
// webpack 2
- new webpack.optimize.OccurrenceOrderPlugin()
]ExtractTextWebpackPlugin - breaking change
ExtractTextPlugin ì´ webpack 2ì í¨ê» ìëíë ¤ë©´ ë²ì 2ê° íìí©ëë¤.
npm install --save-dev extract-text-webpack-plugin
ì´ íë¬ê·¸ì¸ì ì¤ì ë³ê²½ì ì£¼ë¡ êµ¬ë¬¸ì ëë¤.
ExtractTextPlugin.extract
module: {
rules: [
{
test: /.css$/,
- loader: ExtractTextPlugin.extract("style-loader", "css-loader", { publicPath: "/dist" })
+ use: ExtractTextPlugin.extract({
+ fallback: "style-loader",
+ use: "css-loader",
+ publicPath: "/dist"
+ })
}
]
}new ExtractTextPlugin({options})
plugins: [
- new ExtractTextPlugin("bundle.css", { allChunks: true, disable: false })
+ new ExtractTextPlugin({
+ filename: "bundle.css",
+ disable: false,
+ allChunks: true
+ })
]Full dynamic requires now fail by default
ííì(ì¦, require(expr))ë§ ìë ì¢
ìì±ì ì´ì ì ì²´ ëë í°ë¦¬ì 컨í
ì¤í¸ ëì ë¹ ì»¨í
ì¤í¸ë¥¼ ìì±í©ëë¤.
ì´ì ê°ì ì½ëë ES2015 모ëìì ìëíì§ ìì¼ë¯ë¡ 리í©í ë§í´ì¼ í©ëë¤.
ì´ê²ì´ ê°ë¥íì§ ìë¤ë©´ ContextReplacementPluginì ì¬ì©íì¬ ì»´íì¼ë¬ê° ì¬ë°ë¥¸ í´ê²°ì íëë¡ íí¸ë¥¼ ì¤ ì ììµëë¤.
Using custom arguments in CLI and configuration
CLI를 ë¨ì©íì¬ ë¤ìê³¼ ê°ì´ ì¤ì ì ì¬ì©ì ì§ì ì¸ì를 ì ë¬í ê²½ì°.
webpack --custom-stuff
// webpack.config.js
const customStuff = process.argv.includes("--custom-stuff");
/* ... */
module.exports = config;ì´ê²ì´ ë ì´ì íì©ëì§ ììì ì ì ììµëë¤. ì´ì CLIê° ë ì격í´ì¡ìµëë¤.
ëì ì¤ì ì ì¸ì를 ì ë¬í기 ìí ì¸í°íì´ì¤ê° ììµëë¤. ëì ì¬ì©í´ì¼ í©ëë¤. 미ëì ë구ë ì´ê²ì ìì¡´í ì ììµëë¤.
webpack --env.customStuff
module.exports = function (env) {
const { customStuff } = env;
/* ... */
return config;
};CLI를 ì°¸ê³ íì¸ì.
require.ensure and AMD require are asynchronous
ì´ë¬í í¨ìë ì´ì ì²í¬ê° ì´ë¯¸ ë¡ëë ê²½ì° ë기ìì¼ë¡ ì½ë°±ì í¸ì¶íë ëì íì ë¹ë기ìì ëë¤.
require.ensureë ì´ì ë¤ì´í°ë¸ Promiseì ìì¡´í©ëë¤. ê·¸ê²ë¤ì´ ìë íê²½ìì require.ensure를 ì¬ì©íë¤ë©´ í´ë¦¬íì´ íìí ê²ì
ëë¤.
Loader configuration is through options
webpack.config.jsìì ì¬ì©ì ì ì ìì±ì¼ë¡ ë¡ë를 ë ì´ì ì¤ì í ìììµëë¤. optionsì íµí´ ìíí´ì¼ í©ëë¤. ts ìì±ì´ ìë ë¤ì ì¤ì ì ë ì´ì webpack 2ìì ì í¨íì§ ììµëë¤.
module.exports = {
// ...
module: {
rules: [
{
test: /\.tsx?$/,
loader: "ts-loader",
},
],
},
// does not work with webpack 2
ts: { transpileOnly: false },
};What are options?
ì¢ì ì§ë¬¸ì
ëë¤. ìë°í ë§íë©´ 2ê°ì§ë¡ í´ì ê°ë¥íë©°, 모ë webpack ë¡ë를 ì¤ì íë ë°©ë²ì
ëë¤. ê³ ì ì ì¼ë¡ optionsì queryë¼ê³ íì¼ë©° ë¡ë ì´ë¦ì ì¶ê°í ì ìë 문ìì´ì´ììµëë¤. 쿼리 문ìì´ê³¼ ë§¤ì° ì ì¬íì§ë§ ì¤ì ë¡ë ë ê°ë ¥í 기ë¥ì
ëë¤.
module.exports = {
// ...
module: {
rules: [
{
test: /\.tsx?$/,
loader: `ts-loader?${JSON.stringify({ transpileOnly: false })}`,
},
],
},
};ê·¸ë¬ë ë¡ëì í¨ê» ì ê³µëë ë³ëë¡ ì§ì ë ê°ì²´ì¼ ìë ììµëë¤.
module.exports = {
// ...
module: {
rules: [
{
test: /\.tsx?$/,
loader: "ts-loader",
options: { transpileOnly: false },
},
],
},
};LoaderOptionsPlugin context
ì¼ë¶ ë¡ëë 컨í ì¤í¸ ì ë³´ê° íìíê³ ì¤ì ìì ì´ë¥¼ ì½ìµëë¤. ì´ê²ì ì¥ê¸°ì ì¼ë¡ ë¡ë ìµì ì íµí´ ì ë¬ëì´ì¼ í©ëë¤. ê´ë ¨ ìµì ì ë¡ë 문ì를 ì°¸ê³ íì¸ì.
ì´ì ë¡ëìì í¸íì±ì ì ì§í기 ìí´ íë¬ê·¸ì¸ì íµí´ ì´ ì 보를 ì ë¬í ì ììµëë¤.
plugins: [
+ new webpack.LoaderOptionsPlugin({
+ options: {
+ context: __dirname
+ }
+ })
]debug
debug ìµì
ì webpack 1ìì ë¡ë를 ëë²ê·¸ 모ëë¡ ì ííìµëë¤. ì´ê²ì ì¥ê¸°ì ì¼ë¡ ë¡ë ìµì
ì íµí´ ì ë¬ëì´ì¼ í©ëë¤. ê´ë ¨ ìµì
ì ë¡ë 문ì를 ì°¸ê³ íì¸ì.
ë¡ëì ëë²ê·¸ 모ëë webpack 3 ì´ììì ì ê±°ë©ëë¤.
ì´ì ë¡ëìì í¸íì±ì ì ì§í기 ìí´ íë¬ê·¸ì¸ì íµí´ ë¡ë를 ëë²ê·¸ 모ëë¡ ì íí ì ììµëë¤.
- debug: true,
plugins: [
+ new webpack.LoaderOptionsPlugin({
+ debug: true
+ })
]Code Splitting with ES2015
webpack 1ììë require.ensure() 를 ìì© íë¡ê·¸ë¨ì ì²í¬ë¥¼ ì§ì° ë¡ëíë ë°©ë²ì¼ë¡ ì¬ì©í ì ììµëë¤.
require.ensure([], (require) => {
const foo = require("./module");
});ES2015 ë¡ë ì¬ìì import()를 ë°íìì ëì ì¼ë¡ ES2015 모ëì ë¡ëíë ë°©ë²ì¼ë¡ ì ìí©ëë¤. Webpackì import()를 ë¶ë¦¬ì ì¼ë¡ ì²ë¦¬íê³ ìì²ë 모ëì ë³ëì ì²í¬ì ë£ìµëë¤. import()ë 모ë ì´ë¦ì ì¸ìë¡ ì·¨íê³ Promise를 ë°íí©ëë¤.
function onClick() {
import("./module")
.then((module) => module.default)
.catch((err) => {
console.log("Chunk loading failed");
});
}ì¢ì ìì: ì²í¬ ë¡ë ì¤í¨ë Promise 기ë°ì´ê¸° ë문ì ì´ì ì²ë¦¬í ì ììµëë¤.
Dynamic expressions
ë¶ë¶ ííìì import()ì ì ë¬í ì ììµëë¤. ì´ê²ì CommonJSì ííìê³¼ ì ì¬íê² ì²ë¦¬ë©ëë¤(webpackì ê°ë¥í 모ë íì¼ê³¼ í¨ê» contextì ìì±í©ëë¤).
import()ë ê°ë¥í ê° ëª¨ëì ëí´ ë³ëì ì²í¬ë¥¼ ìì±í©ëë¤.
function route(path, query) {
return import(`./routes/${path}/route`).then(
(route) => new route.Route(query),
);
}
// This creates a separate chunk for each possible routeMixing ES2015 with AMD and CommonJS
AMD ë° CommonJSì ê²½ì° ì¸ ê°ì§ 모ë ì íì 모ë ìì ë¡ê² í¼í©í ì ììµëë¤(ëì¼í íì¼ ë´ììë). ì´ ê²½ì° Webpackì babel ë° node-epsì ì ì¬íê² ëìí©ëë¤.
// CommonJS consuming ES2015 Module
const book = require("./book");
book.currentPage;
book.readPage();
book.default === "This is a book";// ES2015 Module consuming CommonJS
import fs from "node:fs"; // module.exports map to default
typeof fs.readFileSync === "function";// ES2015 Module consuming CommonJS
import { readFileSync } from "node:fs"; // named exports are read from returned object+
typeof readFileSync === "function";Webpackì´ ì¬ì©í ì ìëë¡ ì´ë¬í 모ë 기í¸ë¥¼ 구문 ë¶ìíì§ ìëë¡ Babelì ì§ìíë ê²ì´ ì¤ìí©ëë¤.
.babelrc ëë babel-loader ìµì
ìì ë¤ìì ì¤ì íë©´ ë©ëë¤.
.babelrc
{
"presets": [["es2015", { "modules": false }]]
}Hints
무ì¸ê°ë¥¼ ë°ê¿ íìë ìì§ë§ 기íì ëë¤.
Template strings
Webpackì ì´ì ííììì í í릿 문ìì´ì ì§ìí©ëë¤. ì´ë Webpack ì¤ì ìì ì¬ì©í ì ììì ì미í©ëë¤.
- require("./templates/" + name);
+ require(`./templates/${name}`);Configuration Promise
Webpackì ì´ì ì¤ì íì¼ìì Promise ë°íì ì§ìí©ëë¤. ì´ë ê² íë©´ ì¤ì íì¼ìì ë¹ë기 ì²ë¦¬ê° ê°ë¥í©ëë¤.
webpack.config.js
module.exports = function () {
return fetchLangs().then((lang) => ({
entry: "...",
// ...
plugins: [new DefinePlugin({ LANGUAGE: lang })],
}));
};Advanced loader matching
Webpackì ì´ì ë¡ëì ëí´ ì¼ì¹ìí¬ ë ë§ì í목ì ì§ìí©ëë¤.
module.exports = {
// ...
module: {
rules: [
{
resource: /filename/, // matches "/path/filename.js"
resourceQuery: /^\?querystring$/, // matches "?querystring"
issuer: /filename/, // matches "/path/something.js" if requested from "/path/filename.js"
},
],
},
};More CLI options
ì¬ì©í ì ìë ëª ê°ì§ ìë¡ì´ CLI ìµì ì´ ììµëë¤.
--define process.env.NODE_ENV="production" DefinePlugin를 ì°¸ê³ íì¸ì.
--display-depth ë ê° ëª¨ëì ì§ì
ì ê¹ì§ì 거리를 íìí©ëë¤.
--display-used-exports ë 모ëìì ì¬ì©ëë ë´ë³´ë´ê¸° ì 보를 íìí©ëë¤.
--display-max-modules ë ì¶ë ¥ì íìëë 모ëì ì를 ì¤ì í©ëë¤(기본ê°ì 15).
-pë ì´ì process.env.NODE_ENV를 "production"ì¼ë¡ ì ìí©ëë¤.
Loader changes
ë³ê²½ ì¬íì ë¡ë ìì±ììê²ë§ í´ë¹ë©ëë¤.
Cacheable
ì´ì 기본ì ì¼ë¡ ë¡ë를 ìºìí ì ììµëë¤. ë¡ëë ìºìí ì ìë ê²½ì° ìµí¸ììí´ì¼ í©ëë¤.
// Cacheable loader
module.exports = function(source) {
- this.cacheable();
return source;
} // Not cacheable loader
module.exports = function(source) {
+ this.cacheable(false);
return source;
}Complex options
webpack 1 ì ë¡ëì ëí´ JSON.stringify ê°ë¥ ìµì
ë§ ì§ìí©ëë¤.
webpack 2 ë ì´ì 모ë JS ê°ì²´ë¥¼ ë¡ë ìµì ì¼ë¡ ì§ìí©ëë¤.
webpack 2.2.1 ì´ì (ì¦, 2.0.0ìì 2.2.0ê¹ì§), ident를 ì¬ì©íë ë° íìí ë³µì¡í ìµì
ì ì¬ì©íì¬ options ê°ì²´ë¥¼ ì¬ì©íì¬ ë¤ë¥¸ ë¡ëìì ì°¸ê³ í ì ììµëë¤. ì´ë 2.2.1ìì ì ê±°ëìì¼ë¯ë¡ íì¬ ë§ì´ê·¸ë ì´ì
ììë ident í¤ë¥¼ ì¬ì©í íìê° ììµëë¤.
{
test: /\.ext/
use: {
loader: '...',
options: {
- ident: 'id',
fn: () => require('./foo.js')
}
}
}


