# 什么是webpack?*
问题:为什么在 vue 中使用 npm run build 命令就可以把开发环境中的文件进行合并?
答案:无论是 vue 还是 react、angular,使用 cli 创建出来的项目,都自动的把结构做好了,内部的 webpack 也都配置好了,项目开发完毕后,只需要执行 build 命令,就能够把 src 下的文件进行打包,这个打包功能都是由 webpack 完成的,这个配置无需我们自己操作,vue、react、angular 内部已经整合完毕,只需要直接使用命令即可。
**如果想手动的一步一步的配置 webpack,那么可以根据下面的文档进行操作。**
webpack是资源加载/打包工具
```
project1/
src/
dist/
```
说白了,就是把开发环境src目录中的文件,打包到生产环境dist目录下。
- 在安装一个要打包到生产环境的安装包时,应使用 npm i -S,完整写法为 npm install --save lodash
- 如果安装一个用于开发环境的安装包,应使用 npm i -D,完整写法为 npm install --save-dev lodash
> 打包指把src下那些碎片化的文件,合并到一起,生成到dist下。
> 部署指把dist目录当成网站根目录,供别人访问。
# 如何使用webpack?
全局安装
```bash
npm i -g webpack webpack-cli
```
查看版本号
```bash
webpack -v # 4.29.6
webpack-cli -v # 3.3.0
```
创建项目目录
```bash
mkdir project1 && cd project1
```
初始化项目
```bash
npm init
```
> npm init -y (-y参数的作用是创建package.json时都安装默认的来)
局部安装
```bash
npm i -D webpack webpack-cli
```
创建目录结构、文件和内容:
```
project1/
package.json
src/
index.js
```
src/index.js 中的代码:
- 在安装一个要打包到生产环境的安装包时,会打包到线上去并且在线上环境能用到的,应使用 npm i -S,完整写法为 npm install --save lodash
- 如果安装一个用于开发环境的安装包,只需要在开发的时候编译就好,线上并不需用的到,应使用 npm i -D,完整写法为 npm install --save-dev lodash
```javascript
// lodash 是一个js工具库,用来操作 object、array、number... 更方便了
import _ from 'lodash'; // npm install --save lodash
function component(){
var element = document.createElement('div')
element.innerHTML = _.join(['Hello', 'webpack'], ' ')
return element;
}
document.body.appendChild( component() )
```
创建目录结构、文件和内容:
```
project1/
package.json
dist/
index.html
```
dist/index.html 中的代码:
- main.js 文件目前还不存在
- 需要通过webpack把src/index.js文件及其依赖文件lodash打包到一起
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
</body>
</html>
<script src="main.js"></script>
```
在命令行中执行:
```bash
npx webpack
```
执行 npx webpack,会将我们的脚本作为入口起点,然后输出为 main.js
> Node 8.2+ 提供了 npx 命令,可以运行在初始安装的 webpack包(package)的webpack二进制文件
然后就可以浏览dist/index.html网页了
# 配置文件
在项目根目录下建立webpack.config.js文件
```
project1/
webpack.config.js
```
编写代码,配置打包内容。
```javascript
// 在 webpack 中使用 require 引入自带的path模块 (CommomJS规范)
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'dist')
}
}
```
> entry描述的是入口;output描述的是出口。
命令行执行:
```bash
npx webpack --config webpack.config.js
```
说明:根据配置页进行打包,入口为src/index.js,根据入口页的相关依赖,合并到dist/index.js中。
也可以直接执行:
```bash
webpack
```
两个命令是等效的
# NPM脚本
考虑到用 CLI 这种方法来运行本地的 webpack 不是特别方便,我们可以设置快捷方式。
在 package.json 文件的 scripts 对象中,增加 build 脚本,当执行 build 脚本时,实际执行的是 webpack 命令。
```
"scripts":{
"abc" : "npx webpack --config webpack.config.js",
"build": "webpack"
}
```
使用 npm run build 命令,代替之前使用的 webpack 命令。
```bash
npm run build # npm run abc
```
# 资源管理
加载当前项目所用到的其他资源
- 加载 CSS
- 加载图片
- 加载字体
# 加载 CSS
下载在js中解析css的模块,我们要把js和css打包到一起。
```bash
npm install -D style-loader css-loader
```
webpack.config.js 配置规则
```javascript
module.exports = {
entry: ......
output: {} .....
module: {
rules:[
{ test:/\.css$/, use:['style-loader', 'css-loader'] }
]
}
}
```
module.rules表示使用webpack打包模块时所定义的打包规则。
webpack打包时,如果碰到的是.css结尾的文件,使用style-loader和css-loader处理。
- style-loader:将 JS 字符串生成为 style 节点
- css-loader:将 CSS 转换为 CommonJS 模块
src/style.css
```css
.hello { color:red }
```
src/index.js
```javascript
import './style.css'
function component(){
// ........
element.classList.add('hello')
}
```
命令行中执行:
```bash
npm run build
```
如果想使用 scss 文件,需要安装
> npm config set sass-binary-site http://npm.taobao.org/mirrors/node-sass
```
npm install sass-loader node-sass --save-dev
```
然后规则中配置:
```
{ test:/\.scss$/, use:['style-loader', 'css-loader', 'sass-loader'] }
```
# 加载图片
CSS 和 JS 中的图片如何处理?
需要安装:
```
npm install --save-dev file-loader
```
然后在 webpack.config.js 页面中配置规则:
```
{ test:/\.(png|svg|jpg|gif)$/, use:['file-loader'] }
```
创建文件及编写代码
```
src/
images/
1.jpg
2.jpg
index.js
import img from './images/1.jpg'
var myImg = new Image();
myImg.src = img;
document.body.appendChild( myImg );
style.scss
background: url(images/2.jpg)
```
命令行执行:
```
npm run build
```
两张图片会被复制到 dist 目录下面,网页能正常使用,如果想配置图片输出后的路径,可以:
```
use:[{
loader:'file-loader',
options:{
name:'[name].[ext]',
outputPath:'images'
}
}]
```
# 加载字体
字体这种资源需要用到 file-loader 或 url-loader
```
npm i -D url-loader
```
规则配置:(二选一)
- file-loader会保存单独的字体文件
```
{ test: /\.(woff|woff2|eot|ttf|otf)$/, use: ['file-loader'] }
```
- url-loader会和js合并到一起
```
{ test: /\.(woff|woff2|eot|ttf|otf)$/, use: ['url-loader'] }
```
style.css 或 style.scss
```
@font-face{
font-family: abc;
src: url(./fonts/经典毛笔字体.ttf) format("truetype");
}
div{ font-family:"abc" }
```
命令行
```
npm run build
```
# 多入口多出口
PC端项目中可能有很多个入口,比如 index.html,比如 main.html 等,浏览器中都可以直接访问。
> 移动端项目SPA都是单页面应用,用一个入口就可以了,如果是传统的PC端,那么需要用到很多入口页面。
dist/index.html
```html
<script src="index.js"></script>
```
dist/main.html
```html
<script src="main.js"></script>
```
在浏览器中分别访问这两个文件,这两个文件分别依赖的js文件,都是独立的,这就是多入口多出口。
wepack.config.js
```javascript
entry:{
index:'./src/index.js',
main:'./src/main.js'
},
output:{
filename:'[name].js',
path:path.resolve(__dirname, 'dist')
}
```
entry描述的是入口,表示有两个入口 ,一个名字叫做index,一个名字叫做main。
output描述的是出口,filename描述的是打包后文件的名字,[name]是关键字表示entry入口文件名,path表示合并后文件所在位置。
命令行:
```bash
npm run build
```
就能够根据entry的配置打包出2个js文件了
# 插件
安装:
```bash
npm install --save-dev html-webpack-plugin
```
webpack.config.js
```javascript
const HtmlWebpackPlugin = require('html-webpack-plugin')
entry: { ... },
plugins: [ new HtmlWebpackPlugin({title:'标题栏内容'}) ],
output: { ... }
```
HtmlWebpackPlugin 的作用就是在 dist 目录下生成 index.html 文件,
我们现在的项目中存在 dist/index.html 所以命令执行后,会将之前的文件覆盖了,
如果项目中不存在 dist/index.html,那么 HtmlWebpackPlugin 也能够根据默认的配置把这个 index 文件创建出来。
# 清理dist目录
每次执行webpack编译时,最好先把之前的内容清理干净,然后重新生成。
```bash
npm install clean-webpack-plugin --save-dev
```
webpack.config.js
```javascript
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
plugins:[
new CleanWebpackPlugin(),
new HtmlWebpackPlugin...
]
```
# 错误调试
webpack 是把很多个文件捆绑到一起,那么如果有段代码出错了,怎么定位错误?
src/print.js
把 console.log 改为 console.error 模拟一个错误出来,执行 npm run build 重新生成捆绑后的文件,浏览器运行。
浏览器的控制台中会报错,因为我们访问的是生产环境下的代码,所以报的是生产环境下的错误,所以不好定位错误。
webpack.config.js
```javascript
entry:{ ... },
devtool: 'inline-source-map'
```
加上 devtool 配置后,就能够定位到错误了,但要记得这仅仅是为了调试,生产时要关闭。
# 自动编译和自动刷新
每次修改文件后,都需要手动 npm run build 这太麻烦了,所以可以安装
```
npm install --save-dev webpack-dev-server
```
webpack.config.js
```javascript
devtool: 'inline-source-amp',
devServer: { contentBase: './dist' } //把dist看作是一个根目录去运行
```
package.json
```javascript
"scripts":{
"start" : "webpack-dev-server --open"
}
```
命令行运行
```bash
npm start
```
然后直接修改 src 下的文件,在浏览器中浏览 dist 下的文件,看效果。
# 别名
可以把长的文件名配置短的别名,这样描述依赖文件时会方便一些。
```javascript
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
resolve:{
alias: {
'@': path.resolve('src'),
'#': path.resolve('src/images'),
'fa': path.resolve('src/fonts/font-awesome-4.7.0/css'),
}
},
```
使用别名
```javascript
import printMe from '@/print.js'
import img from '#/1.jpg';
import 'fa/font-awesome.min.css'
```
> 不能用$当别名,修改webpack.config.js后要重新npm start
# 代理
解决跨域问题的一种方案
```javascript
devServer: {
contentBase: './dist',
proxy:{
"/api": {
target: "http://www.wyyijiaqin.com",
pathRewrite: { '^/api': '' },
//secure: false,
changeOrigin: true,
}
}
},
```
> 启动 devServer ,该代理才有作用。
# 打包时,代码是否压缩?
mode属性可以定义打包时代码是否压缩。
- development 不压缩代码
- production 压缩代码,默认
```javascript
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
mode: "development"
```
# post-css
```bash
cnpm i postcss-loader -D
cnpm i autoprefixer -D # 处理css浏览器兼容
```
这个模块是用来处理css兼容的,会自动给css加上浏览器前缀,如-ms- -webkit- 等
**style/index.css**
```css
span{
background: red;
color:white;
display: flex;
flex: 1;
transform: translate(-50%, -50%)
}
```
**index.js**
```javascript
import './style/index.css';
```
**webpack.config.js**
```
{
test: /\.css$/,
use: ['style-loader', 'css-loader', {
loader: 'postcss-loader',
options:{
plugins: [
require('autoprefixer')("last 100 versions")
]
}
}]
}
```
> require('autoprefixer')("last 100 versions") 参数改了就会出错。
语义:如果碰到css文件,先用style-loader和css-loader 处理,然后用postcss-loader处理,使用require引入autoprefixer模块,处理css兼容
# 多个 config 文件入口
配置独立的 config 文件
比如我希望开发环境中,使用map,即出错时,能够看到错误内容,而生产环境下,出错时,不希望看到出错的具体内容,而且生产环境下的map还影响了文件的体积,所以应该去掉。
```bash
npm install --save-dev webpack-merge
```
**通用配置 common.js**
```javascript
const path = require('path');
module.exports = {
entry: {
index: './src/index.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
};
```
**开发环境的配置 dev.js**
```
const merge = require('webpack-merge');
const common = require('./common.js');
module.exports = merge(common, {
devtool: 'inline-source-map',
devServer: {
contentBase: './dist'
}
});
```
**生产环境的配置 prod.js**
```
const merge = require('webpack-merge');
const common = require('./common.js');
module.exports = merge(common, {
});
```
**package.json**
```
"scripts": {
"start": "webpack-dev-server --open --config dev.js",
"build": "webpack --config prod.js"
}
```
执行 npm start 相当于开启了开发环境的服务,如果出错了,检查是不是某类文件类型的合并规则没有被定义。
执行 npm run build 表示根据开发环境中的文件,合并成生产环境下的文件。