webpack基本介绍
webpack是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)
现代 javascript 应用程序的 静态模块打包器 (module bundler)
- 静态: 文件资源
- 模块: node环境, 引入文件, 遵守模块化语法
除了合并代码, 还可以翻译和压缩代码
- less/sass -> css
- ES6/7/8 -> ES5
- html/css/js -> 压缩合并
准备
环境准备:它是基于nodejs,所以本机一定要先安装了node。
项目准备:webpack是用来对已有项目进行打包,所以一定是在某个项目下进行应用打包。
webpack是一个工具,对于所有的项目都可以来使用,从这个意义上来讲,它是可以去全局安装的,但是,考虑到不同的项目中可能使用了不同的webpack版本,所以不推荐大家去全局安装。特别是打开一个老项目时,一定要注意一下它的webpack的版本号。
前端很多悲惨故事,都是是从版本不一致开始的。
采用局部安装的方式来安装它,注意,它只是一个开发依赖,并不是生产依赖,所以在命令行中加上-D。
命令如下:npm i webpack webpack-cli -D // --save-dev
下面来通过命令行工具来检查是否安装成功。
准备代码
创建三个文件index.html,index.js,tool.js,最后的项目结构是:
项目名
├── index.html
├── index.js
├── tool.js
└── package.json
# 第一种:
node_modules\.bin\webpack -v
# 第二种:
npx webpack -v
注意:
- 由于webpack并不是全局安装的,所以并不能直接使用
webpack -v来做检验。 - npx是npm5.2之后提供的新功能。可以通过
npx -v来检测它的版本。 在这里,我们通过它来调用项目安装的模块,它在运行时会在node_modules/.bin中去检查命令是否存在。
在tool.js导出模块
它用来提供一个方法,供其它模块来使用。这里使用commonjs规范(就是node.js中的导出模块的方式)导出工具方法。
在index.js中导入模块
在index.js中引入tool.js中的定义的方法。注意,这里已经涉及到了在一个js中引用另一个js
const { updateDom } = require('./tool')
updateDom ('app','index.html')
由于现在在index.js使用了require这种模块化的处理方式,所以它无法直接在浏览器中使用,如果直接在index.html中引用,浏览器会报错。
我们接下来就需要使用webpack命令来对index.js进行处理了。
使用webpack来做打包
命令格式是:npx webpack 文件名
这里的操作是:
npx webpack ./index.js
如果没有遇到错误,会看到类似的结果如下:
$ npx webpack ./index.js
Hash: b43d4771990a46286152
Version: webpack 4.42.1
Time: 101ms
Built at: 2020-04-01 3:15:48 PM
Asset Size Chunks Chunk Names
main.js 1.04 KiB 0 [emitted] main
Entrypoint main = main.js
[0] ./index.js 71 bytes {0} [built]
[1] ./tool.js 136 bytes {0} [built]
它说明打包操作已经成功:index.js和tool.js已经合成了一个main.js文件了。
把上面打包完成的main.js引入到index.html
小结
- 为啥要用webpack?
-
- 有效处理模块化。默认情况下,浏览器并不支持模块化,而我们的前端项目又使用了模块化,有了webpack之后,就可以突破这个限制了。
- webpack可以把多个相互引用的.js文件打包成一个文件,且文件有加密,压缩的效果,上线更安全。
- 这个过程中nodejs起了什么作用?
-
- 它是webpack的运行基础,没有了nodejs环境,就无法做类似于文件读写的操作了。
- 最终生成的main.js并不是在nodejs环境中运行的,整个的项目效果还是在浏览器中运行的。
配置文件的作用
设置入口和出口
在配置文件中,配置自定义的入口和出口
入口和出口
入口文件: 指定了webpack从哪个文件开始工作。在它的内部会引入其他的模块,这样在打包时就会「顺藤摸瓜」也将其他的文件打包进来。
出口文件:指定了最后打包之后的文件,重点是这个文件的具体位置。
在webpack中,默认的入口和出口分别是:
- 默认入口是:./src/index.js
- 默认出口是:./dist/main.js。
也就是说,如果直接在根目录下运行webpack,它会直接去找.src下的index.js,并把打包之后的代码放在dist/main.js下。
了解默认入口文件
修改目录结构,新建一个src目录,并把index.js,tool.js,tooles6.js移动到它下面。
项目名
├── index.html
├── src
│ ├── index.js
│ └── tool.js
└── package.json
直接省略入口文件,直接打包: npx webpack 由于在src目录已经存在index.js
设置入口文件
需求:希望:
这个入口文件不是index.js,而是main.js 整体js文件不是放在src目录下,而是src/js下
解决:
(1) 调整目录结构如下:
项目名
├── index.html
├── src
│ └── js
│ ├── main.js
│ └── tool.js
├── webpack.config.js # webpack的配置文件
└── package.json
(2) 然后,修改配置项
- 修改src/index.js的名字为src/js/main.js
- 在webpack.config.js的配置项中添加
entry项
module.exports = {
mode: 'development', // 打包方式
entry:'./src/js/main.js' // 入口文件
}
- 重新打包,测试。
指定出口文件
在webpack.config.js中设置output项。
目标: 把出口文件设置为在build目录下的bundle.js
// 引入nodejs中的核心模块
const path = require('path')
console.log(path.join(__dirname,'/build'))
module.exports = {
mode: "production",
entry: './src/js/main.js', // 入口文件
output: {
"path": path.join(__dirname,'/build'), // 决定出口文件在哪里
"filename": "bundle.js" // 设置出口文件的名字。默认情况下,它叫main.js
}
}
注意:
- output中的filename用来指定打包后的文件名字。
- output中的path用来指定打包后的路径。注意:它必须是绝对路径。所以,这里引用path模块中的join和__dirname来生成绝对路径。
- 如果path中的路径不存在,它会自动创建。
修改打包模式
webpack.config.js中的mode项用来设置打包的方式,如果不设置,会默认为production。
module.exports = {
mode:"development"
}
webpack给mode 提供了两个模式:
● development :开发模式(代码不会压缩 混淆)
● production:生产模式(压缩,混淆,加密....... 不可读)
在打包时指定配置文件
下面,自已创建一个webpack.dev.js的文件,用它来做配置文件。
在项目根目录下创建webpack.dev.js,内容如下:
module.exports = {
output:{
filename:'boundle.js'
}
}
下面,希望使用这个配置文件中的设置来打包。
它的格式是:
npx webpack --config webpack的配置文件
运行命令:
npx webpack --config webpack.dev.js
简化打包命令
可以在package.json中添加script命令来快速启动webpack,格式如下:
"scripts": {
"自定义命令名": "要具体执行的代码",}
例如:
"scripts": {
"dev": "webpack --config webpack.dev.js",
"build": "webpack",
"test": "echo "Error: no test specified" && exit 1"
}
这样 ,我们就得到了两个可以执行的命令: dev, build 。
可以在根目录下的小黑窗中通过:
npm run build, npm run dev 来运行
loader处理css文件
如何引入css文件呢?
传统开发中:css样式是通过在.html文件中通过link标签引入的。但是,现代开发中,我们会把css文件看做资源,直接在.js文件中导入。
下面,我们来具体讨论如何处理.css文件。
创建.css文件
项目名
├── index.html
├── src
│ ├── css
│ │ ├── public.css
│ │ └── style.css
│ └── js
│ ├── main.js
│ ├── tool.js
│ └── tooles6.js
└── package.json
src/css/public.css的内容如下
body,html{
padding:0;
font-size:14px;
}
src/css/style.css的内容如下
@import "public.css";
div {
border:4px solid #ccc;
width: 50%;
height: 200px;
margin:30px auto;
box-shadow: 3px 3px 3px #ccc;
background-color: #fff;
text-align: center;
}
说明:css的@import语句用来导入另一个css文件。
在.js中导入css
在js文件中引入css,就像vue项目中引入第三方ui样式一样,如element-ui的使用说明中提到的:
import Vue from 'vue';
import ElementUI from 'element-ui';
// 引入 css
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';
Vue.use(ElementUI);
new Vue({
el: '#app',
render: h => h(App)
});
很明显,上面的.js代码中引入了.css。
下面,我们修改自已的main.js,在 src/js/main.js中,引入css。
// nodejs中的模块化
const { updateDom } = require('./tool')
// es6中的模块化
import {log} from './tooles6'
+ import '../css/style.css'
updateDom ('app','index.html')
log('test')
再次,打包代码,会报错,具体的保存信息如下:
ERROR in ./src/css/style.css 1:0
Module parse failed: Unexpected character '@' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> @import "public.css";
| div {
| padding:20px;
@ ./src/js/main.js 4:0-26
上面报错的原因是:webpack把.css文件内容当作了js代码来运行,那当然会报错了。所以,解决方法是安装相应的loader来处理。
安装并使用css-loader
对于loader的使用,其基本步骤是一致的,分成两步:
- 安装npm包
- 配置webpack.config.js中的module
安装
安装包的命令是:npm i css-loader -D 。它也是开发依赖。
在配置文件中使用
修改webpack.config.js文件,添加module
const path = require('path')
module.exports = {
mode: 'development',
entry:'./src/js/main.js',
output:{
path:path.resolve(__dirname, './build'),
filename:'bundle.js'
},
+ module:{ // 处理非js模块
+ rules:[ // 规则
+ {
+ test: /.css$/, // 正则测试
+ use: ['css-loader'] // loader
+ }
+ ]
+ }
}
再次打包
它不会报错。但是,页面上也并没有出现样式的效果。打包之后的文件中并没有包含css代码。
安装并使用style-loader
如果我们希望样式生效,最终在.html文件中有两种情况:
- 有style标签
- 有link标签
而css-loader只是能让你在.js中通过import来引入.css,如果你希望引入的css代码最终以style标签的方式插入到html页面中,则还需要安装一个loader:style-loader
安装
npm i style-loader -D
配置
const path = require('path')
module.exports = {
mode: 'development',
entry:'./src/js/main.js',
output:{
publicPath:'https://www.baidu.com',
path:path.resolve(__dirname, './build'),
filename:'bundle.js'
},
module:{ // 处理非js模块
rules:[ // 规则
{
test: /.css$/, // 正则测试
use: ['style-loader','css-loader'] // loader
}
]
}
}
Tip: 在有多个loader的情况下,use数组中的loader执行顺序是从右到左的过程。即:
- 先用css-loader来处理css
- 再用style-loader把css代码插入到html中的style标签中。
loader处理less文件
如果希望处理less文件,则还需要去安装额外的包。
创建less文件
在src目录的less目录下创建 index.less,
项目名
├── index.html
├── src
│ ├── less
│ │ └── index.less
│ ├── css
│ │ ├── public.css
│ │ └── style.css
│ └── js
│ ├── main.js
│ ├── tool.js
│ └── tooles6.js
└── package.json
则内容如下:
@import "../css/style.css";
body{
div {
color: red;
}
}
在.js中引用.less
在src/js/main.js文件中引入less
// nodejs中的模块化
const { updateDom } = require('./tool')
// es6中的模块化
import {log} from './tooles6'
- import '../css/style.css'
+ import '../less/index.less'
updateDom ('app','index.html')
log('test')
安装包
参考官网
npm i less-loader less -D
-------------------------
+ less@3.11.2
+ less-loader@6.1.0
added 50 packages from 123 contributors in 23.883s
- less 用来把less-->css
- less-loader用来加载less文件。
配置模块
在rules中添加一个配置,专门针对less文件。
module.exports = {
// 非js模块,在这里处理
module: {
rules: [ // 规则
{
test: /.css$/, // 正则匹配,以.css结尾的文件
// 如果发现是.css文件,则由如下两个loader来处理
// 处理的顺序是 从右向左
// css-loader: 作用是允许.js中引入.css
// style-loader:作用是在.html上创建style标签,把css代码输入进去
use: ['style-loader','css-loader'] // 匹配成功,使用指定的loader
},
+ {
+ test: /.less$/, // 正则匹配,以.less结尾的文件
// 如果发现是.less文件,则由如下三个loader来处理
// 处理的顺序是 从右向左
// less-loader: 作用是加载less文件,会帮你less转成css
// css-loader: 作用是允许.js中引入.css
// style-loader:作用是在.html上创建style标签,把css代码输入进去
+ use: ['style-loader','css-loader','less-loader'] // 匹配成功,使用指定的loader
+ }
]
}
}
注意:如上配置中,对于less文件的处理涉及三个loader,其处理顺序是less-loader --> css-loader-->style-loader。
- less-loader:用来加载less文件,并处理成css
- css-loader:用来加载css文件
- style-loader:用来将css代码以style标签的格式插入到html文件中
处理资源文件
目标:处理资源文件。假设在css中引入图片,要怎么处理呢?
在项目中引入图片
在src下新增目录,img,并在其下放置两张图片。注意:一张图片大一些,一张图片小一些(可以自行决定)。
-
- webpack.png: 49.4kb
- webpack.svg: 3kb
项目名
├── index.html
├── src
│ ├── less
│ │ └── index.less
│ ├── img
│ │ ├── webpack.png
│ │ └── webpack.svg
│ ├── css
│ │ ├── public.css
│ │ └── style.css
│ └── js
│ ├── main.js
│ ├── tool.js
│ └── tooles6.js
└── package.json
使用图片
两种方式使用图片:
- 作为css的背景图
- 作为独立的图片资源使用
在style.css中引入图片,作为div标签的background。
@import "public.css";
div {
border:4px solid #ccc;
width: 50%;
height: 200px;
margin:30px auto;
box-shadow: 3px 3px 3px #ccc;
background-color:pink;
text-align: center;
+ background-image: url('../img/webpack.svg')
}
在src/main.js中,通过代码 - 把大图插入到创建的img标签上, 添加body上显示
// 引入图片-使用
import imgUrl from '../img/webpack.png'
const theImg = document.createElement("img")
theImg.src = imgUrl
document.body.appendChild(theImg)
配置
webpack5内置处理方案, 只需要填入配置即可 参考:asset module资源模块文档
webpack.config.js中的内容如下
module: {
rules: [
// ...省略其他
{
test: /.(png|jpg|gif|jpeg)$/i, // 匹配图片文件
type: 'asset' // 在导出一个 data URI 和一个单独的文件之间自动选择
}
]
}
- 打包后运行dist/index.html观察区别