Webpack 是当下最热门的前端资源模块化管理和打包工具。它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分隔,等到实际需要的时候再异步加载。通过 loader 的转换,任何形式的资源都可以视作模块,比如 CommonJs 模块、 AMD 模块、 ES6 模块、CSS、图片、 JSON、Coffeescript、 LESS 等。
webpack在开发中可以使用 JavaScript 处理你的依赖关系和加载顺序,避免意外引入一些你不需要在生产中用上的 CSS 样式表和 JS 库,使项目膨胀,或重复载入某些js,css等库。
mkdir webpack-demo && cd webpack-demo
npm init -y
创建并进入webpack-demo,初始化一个新的项目,并创建package.json文件,’-y’表示可接受package.json的一对默认值(多个npm使用技巧)
创建目录结构:
├── src
│ ├── main.js
│ ├── assets
│ │ ├── css
│ │ └── img
├── README.md
├── index.html
├── package.json
├── webpack.config.js
└── yarn.lock
npm i webpack -D
配置信息
1. 入口(entry):告诉webpack打包从哪里开始
2. 输出(output):如何处理打包代码及打包输出到什么位置
3. 加载器(loaders):通过loader识别出各种资源,将这些文件转换为模块
4. 插件(plugins):由于加载器仅基于单个文件执行转换,插件可以做一些更复杂的操作及自定义功能
简单配置
module.exports = {
entry: './src/main.js',
output: {
filename: './dist/bundle.js'
}
}
运行
webpack
dist目录下生成bundle.js文件
webpack其他参数
* webpack -p – 进行优化压缩处理,相当于设置process.env.NODE_ENV="production"
* webpack --watch – 持续监听构建
* webpack -d – debug模式,包含source maps
* webpack --display-error-details - 显示详细的打包出错信息
* webpack -h 查看更多的信息,常见的还有--colors,--progress
* webpack --config XXX.js //使用另一份配置文件(比如webpack.config2.js)来打包
栗子:
{
test: /\.js$/,
loader: 'babel-loader',
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/,
}
loader是比较核心的一块内容,它将各类静态资源通过loader转换为js模块,一个loader包含以下几部分
test: 一个匹配loaders所处理的文件的拓展名的正则表达式(必须)
loader: loader的名称(必须)
include/exclude: 添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选)
query: 为loaders提供额外的设置选项(可选)
babel-loader安装相应的包
npm i babel-loader -D
安装babel-core和babel-preset-es2015,将ES6的代码转换成ES5
npm i babel-core babel-preset-es2015 -D
在module.rules中添加loader节点
module: {
rules: [{
test: /\.js$/,
loader: 'babel-loader',
query: {presets: ['es2015']}
}]
}
src/assets/css下新建style.css
body {
background-color: #ff0;
}
main.js中引入css资源,会报错,因为没有相应的loader进行处理
require(‘./assets/css/style.css’)
添加loader处理
npm i css-loader style-loader -D
{
test: /.css$/,
loader: ‘style-loader!css-loader’
}
在编译的js代码中我们可以看到
/* 4 */
/***/ (function(module, exports, __webpack_require__) {
exports = module.exports = __webpack_require__(1)(undefined);
// imports
// module
exports.push([module.i, "body {\n background-color: #ff0;\n}\n", ""]);
// exports
/***/ }),
url-loader是对file-loader的封装
npm i file-loader url-loader -D
{test: /.(png|jpg)$/, loader: “url-loader?limit=8192”}
这样会将小于8kb的图片直接以base64的格式内嵌到代码中,在一定程度上减少小图片的请求
main.js中添加代码
let img1 = document.createElement('img')
img1.src = require('./assets/img/icon.png')
document.body.appendChild(img1)
更多的loaders:http://webpack.github.io/docs/list-of-loaders.html
dist下新建index.html
<html>
<head>
<title>webpack demo pagetitle>
head>
<body>
<script src="/dist/bundle.js">script>
body>
html>
安装相应的包
npm i webpack-dev-server -D
model下添加配置
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: false,
inline: true,
port: 8080
}
运行
node_modules/.bin/webpack-dev-server
打开 http://127.0.0.1:8080/ 页面变为黄色
我们可以将这个脚本放在package.json中
"scripts": {
"start": "node_modules/.bin/webpack",
"serve": "node_modules/.bin/webpack-dev-server"
}
这样我们可以直接运行
npm run serve
加入进程守护nodemon
"scripts": {
"start": "nodemon --exec webpack -w webpack.config.js",
"serve:watch": "nodemon --exec webpack-dev-server -w webpack.config.js"
}
It’s like LiveReload for every module.
当模块发生变化时,内存中的bundle会收到通知,如果不影响到整个页面的变化,只会刷新局部,而不用刷新整个页面。
devServer: {
contentBase: path.join(__dirname, ''),
compress: true,
inline: true,
hot: true, **
port: 8080
},
2.添加到pligins中
plugins: [
new webpack.HotModuleReplacementPlugin() //热加载插件
],
[HMR] Waiting for update signal from WDS...
[WDS] Hot Module Replacement enabled.
nodemon进程守护,用来监控你node.js源代码的任何变化,自动重启服务
npm i nodemon -g
nodemon - -exec webpack -w webpack.config.js
这里我们只需要监听webpack.config.js文件的变化,所以添加-w参数指定特定的目录或者文件
目录结构
├── src
│ ├── main.js --主入口
│ ├── assets
│ │ ├── css
│ │ └── img
│ ├── libs
│ │ └── util.js --公共方法
│ ├── modules
│ │ ├── login.js --登录页面
│ │ └── product.js --商品页面
├── README.md
├── index.html
├── package.json
├── webpack.config.js
└── yarn.lock
entry的配置我们可以是string,object,array类型,前面的例子用到的是string,单个入口,现在我们添加了几个目录及文件
entry: {
main: './src/main.js',
login: './src/modules/login.js',
product: './src/modules/product.js'
}
上面的入口文件都在src目录下,那么可以设置一个基础目录,绝对路径,用于从配置中解析入口起点(entry point)和加载器(loader)
context
The base directory (absolute path!) for resolving the entry option. If output.pathinfo is set, the included pathinfo is shortened to this directory.
入口文件的基础目录(绝对路径!)。如果output.pathinfo设置,值为到该目录的路径。
更多webpack基础配置
context: path.resolve(__dirname, 'src'),
entry: {
main: './main.js',
login: './modules/login.js',
product: './modules/product.js'
}
如果是数组,那么会将数组中的模块合并,并且输出最后一个;如果是object,那么多个入口的key会打包成包的chunk名称。
output: {
path: path.join(__dirname, 'dist'),
publicPath: '/',
filename: '[name]-[hash:8].js',
chunkFilename: '[id]-[chunkhash].js'
}
跑webpack会看到dist下生成login-5ccbce5e.js,main-5ccbce5e.js,product-5ccbce5e.js三个文件
可以直接写util,而不用util.js, vue文件也可以省略文件名
resolve: {
extensions: ['', '.js', '.vue']
}
resolve: {
extensions: ['.js', '.css'] ,
alias: {
'libs': path.resolve(__dirname, 'src/libs'),
'react': 'node_modules/react/react.js'
}
}
这样在src下的任何js文件都可以直接这样引入模块,而不用../libs/util
import { ajax } from ‘libs/util’
自动加载模块,ProvidePlugin可以让我们无需引入的情况下,以全局的模式直接使用模块变量
new webpack.ProvidePlugin({
Vue: ‘Vue’
})
代码中可以不用引入vue直接使用vue