阮一峰老师的webpack教程,这个webpack-demo 基于webpack 3.10.0 ,与最新的webpack配置可能存在差别。
https://github.com/ruanyf/webpack-demos
demo01
这是最简单的一个配置,entry 配置入口文件地址,output配置目标文件地址。
生成后的文件是经过压缩的。
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};
demo02
多入口文件,一个目标文件。filename 文件名生成后为 bundle1和bundle2, 使用[name] 作为标识
module.exports = {
entry: {
bundle1: './main1.js',
bundle2: './main2.js'
},
output: {
filename: '[name].js'
}
};
demo3
module.exports = {
entry: './main.jsx',
output: {
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015', 'react']
}
}
}
]
}
};
这里有几个信息。输入的文件不再是js,因此需要引入babel-loader, 这个在package.json中有引入
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
通过babel-loader,将jsx文件转换成js文件。rules 配置的细节先不做探究,那是loader的行为。
另外,main.jsx中有对 react和react-dom的引入,其实是react-router包产生的依赖。
demo04
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
module: {
rules:[
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
},
]
}
};
入口文件和目标文件都是js文件,但不同的是: 入口js文件引入了一个css文件
require('./app.css');
因此需要style-loader和css-loader, 事实上它会从后向前解析,先调用css-loader解析css,再调用style-loader将样式添加到头部的逻辑加上。
demo05
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
module: {
rules:[
{
test: /\.(png|jpg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192
}
}
]
}
]
}
};
这个例子引入了图片资源,
注意它使用的是url-loader, 这个loader是图片的获取url后返回到当前位置。
留意到options的limit参数,单位是字节,凡是小于这个字节数的图片文件,都会转成base64字符串,不大于的才返回url。
另外还有其它选项:
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
include: [resolve('static'),resolve('src')],
options: {
limit: 100000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
}
name就是自定义image的路径以及name,include就是你想让哪个文件夹里面的图片进行url-loader转换
demo06
module.exports = {
entry: './main.jsx',
output: {
filename: 'bundle.js'
},
module: {
rules:[
{
test: /\.js[x]?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015', 'react']
}
}
},
{
test: /\.css$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
modules: true
}
}
]
}
]
}
};
这个demo展示了如何多个loader同时使用的状况。另外展示了use参数的多种传值方式。
use的参数可以是:字符串数组,对象,对象数组。
在这里看到css-loader的options参数有个modules,实际上每个loader有不一样的参数。
demo06
var webpack = require('webpack');
var UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
plugins: [
new UglifyJsPlugin()
]
};
这个例子展示了插件的使用。
插件通过plugins 数组引入。
UglifyJsPlugin 插件的作用是将js进行压缩
如果不用这个插件,看看文件大小
Asset Size Chunks Chunk Names
bundle.js 537 bytes 0 [emitted] main
[0] ./main.js 118 bytes {0} [built]
如果用这个插件
Asset Size Chunks Chunk Names
bundle.js 537 bytes 0 [emitted] main
[0] ./main.js 118 bytes {0} [built]
大小一样?翻车了,看到怀疑人生。。。
这个先不管吧
demo08
var HtmlwebpackPlugin = require('html-webpack-plugin');
var OpenBrowserPlugin = require('open-browser-webpack-plugin');
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
plugins: [
new HtmlwebpackPlugin({
title: 'Webpack-demos',
filename: 'index.html'
}),
new OpenBrowserPlugin({
url: 'http://localhost:8080'
})
]
};
这里展示了另外两个插件
HtmlwebpackPlugin
该插件的作用
为html文件中引入的外部资源如script、link动态添加每次compile后的hash,防止引用缓存的外部文件问题
可以生成创建html入口文件,比如单页面可以生成一个html文件入口,配置N个html-webpack-plugin可以生成N个页面入口
当你的入口文件是js文件时,用这个插件可以自动生成一个入口html文件,将生成后的js文件插入到Html中
运行
npm run build
打印出信息
Child html-webpack-plugin for "index.html":
1 asset
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] (webpack)/buildin/module.js 517 bytes {0} [built]
+ 2 hidden modules
既然如此,尝试增加一个页面
plugins: [
new HtmlwebpackPlugin({
title: 'Webpack-demos',
filename: 'index.html'
}),
new HtmlwebpackPlugin({
title: 'Webpack-demos',
filename: 'entry.html'
}),
new OpenBrowserPlugin({
url: 'http://localhost:8080'
})
]
成功生成了两个页面
Child html-webpack-plugin for "index.html":
1 asset
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] (webpack)/buildin/module.js 517 bytes {0} [built]
+ 2 hidden modules
Child html-webpack-plugin for "entry.html":
1 asset
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] (webpack)/buildin/module.js 517 bytes {0} [built]
+ 2 hidden modules
OpenBrowserPlugin
运行
npm run dev
编译后自动打开浏览器,可以看到浏览器的端口号就是参数指定的端口号。每个插件都有不同的功能参数,应该逐个研究,这里就只是了解吧。
demo09
webpack.config.js
var webpack = require('webpack');
var devFlagPlugin = new webpack.DefinePlugin({
__DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'false'))
});
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
plugins: [devFlagPlugin]
};
main.js
document.write('<h1>Hello World</h1>');
if (__DEV__) {
document.write(new Date());
}
从代码可以看到, DefinePlugin插件定义了一个全局变量,注入到js中,js中可以直接使用
demo10
webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};
main.js
require.ensure(['./a'], function(require) {
var content = require('./a');
document.open();
document.write('<h1>' + content + '</h1>');
document.close();
});
可以看到,webpack.config.js其实没有变化。关键在main.js 里面使用了require.ensure方法 。
这应该是一个异步引入模块的方法。在找这个模块的时候,webpack 会自动把这个模块单独打包。
单页应用的路由页面独立出一个js文件,还有异步组件应该就是使用这种机制。
Asset Size Chunks Chunk Names
0.bundle.js 110 bytes 0 [emitted]
bundle.js 6.05 kB 1 [emitted] main
[0] ./a.js 33 bytes {0} [built]
[1] ./main.js 171 bytes {1} [built]
它会将模块打包成0.bundle.js文件,
然后在bundle.js文件中引入。
__webpack_require__.e/* require.ensure */(0).then((function(require) {
var content = __webpack_require__(0);
document.open();
document.write('<h1>' + content + '</h1>');
document.close();
}).bind(null, __webpack_require__)).catch(__webpack_require__.oe);
这个打包后的bundle.js其实是使用了jsonp的方法去实现的。
webpack_require 这种模块化加载形式从demo08 开始,就在bundle.js中出现,之前的只是简单地对文件转换,压缩。
然而demo08并没有引入模块。所以,它除了跟入口文件引入模块有关,还跟插件本身的处理有关。
demo11
main.js
var load = require('bundle-loader!./a.js');
load(function(file) {
document.open();
document.write('<h1>' + file + '</h1>');
document.close();
});
webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};
main.js中使用了bundle-loader加载模块,这是在文件中使用loader,而非webpack配置
demo12
var webpack = require('webpack');
module.exports = {
entry: {
bundle1: './main1.jsx',
bundle2: './main2.jsx'
},
output: {
filename: '[name].js'
},
module: {
rules:[
{
test: /\.js[x]?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015', 'react']
}
}
},
]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "commons",
// (the commons chunk name)
filename: "commons.js",
// (the filename of the commons chunk)
})
]
}
main1.jsx
var React = require('react');
var ReactDOM = require('react-dom');
ReactDOM.render(
<h1>Hello World</h1>,
document.getElementById('a')
);
main2.jsx
var React = require('react');
var ReactDOM = require('react-dom');
ReactDOM.render(
<h1>Hello World</h1>,
document.getElementById('a')
);
main1.jsx和main2.jsx两个文件都引入了react和react-dom, 在webpack配置中,CommonsChunkPlugin可将共同引入的模块抽出来,打包到common.js中。(其实,只要引了这个插件,即使没有公共的模块,也会生成common.js)
demo13
var webpack = require('webpack');
module.exports = {
entry: {
app: './main.js',
vendor: ['jquery'],
},
output: {
filename: 'bundle.js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor.js'
})
]
};
main.js
var $ = require('jquery');
$('h1').text('Hello World');
在main.js中引入了jquery, 在entry中定义vendor,可以将指定的模块打包到公共包中。
如果在entry中将vendor注释掉,生成的vendor.js中,不会包含jquery,而是被包含到了bundle.js中
Asset Size Chunks Chunk Names
bundle.js 289 kB 0 [emitted] [big] app
vendor.js 5.78 kB 1 [emitted] vendor
demo14
module.exports = {
entry: './main.jsx',
output: {
filename: 'bundle.js'
},
module: {
rules:[
{
test: /\.js[x]?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015', 'react']
}
}
},
]
},
externals: {
// require('data') is external and available
// on the global var data
'data': 'data'
}
};
main.jsx
var data = require('data');
var React = require('react');
var ReactDOM = require('react-dom');
ReactDOM.render(
<h1>{data}</h1>,
document.body
);
该例展示了externals 选项的用法,定义了一个data变量,在main.jsx中require获得,可以直接使用。
试与 demo09的DefinePlugin插件比较
demo15
module.exports = {
entry: './index.js',
output: {
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015', 'react']
}
}
},
]
}
};
index.js
import React from 'react';
import { render } from 'react-dom';
import { BrowserRouter, Switch, Route, Link } from 'react-router-dom';
import './app.css';
// ref https://stackoverflow.com/questions/46482433/reactjs-createclass-is-not-a-function
class App extends React.Component {
render() {
return (
<div>
<header>
<ul>
<li><Link to="/app">Dashboard</Link></li>
<li><Link to="/inbox">Inbox</Link></li>
<li><Link to="/calendar">Calendar</Link></li>
</ul>
Logged in as Jane
</header>
<main>
<Switch>
<Route exact path="/" component={Dashboard}/>
<Route path="/app" component={Dashboard}/>
<Route path="/inbox" component={Inbox}/>
<Route path="/calendar" component={Calendar}/>
<Route path="*" component={Dashboard}/>
</Switch>
</main>
</div>
);
}
};
class Dashboard extends React.Component {
render() {
return (
<div>
<p>Dashboard</p>
</div>
);
}
};
class Inbox extends React.Component {
render() {
return (
<div>
<p>Inbox</p>
</div>
);
}
};
class Calendar extends React.Component {
render() {
return (
<div>
<p>Calendar</p>
</div>
);
}
};
// ref https://segmentfault.com/q/1010000009616045/a-1020000009618728
render((
<BrowserRouter>
<Route path="/" component={App} />
</BrowserRouter>
), document.querySelector('#app'));
展示了一个较为综合的react例子
网友评论