webpack基础用法
一、webpack是什么
-
webpack是一种前端资源构建(打包)工具,一个静态模块打包器
-
在webpack看来,前端所有资源文件(js/json/css/images/less/scss...)都会作为模块处理
-
webpack根据模块的依赖关系进行静态分析,打包生成对应的静态资源
-
webpack可以解决当前web开发中所面临的困境,它提供了:
-
友好的模块化支持
-
代码压缩混淆
-
处理js兼容问题
-
性能优化
-
隔行换色案例:没有使用webpack,浏览器不能兼容模块语法,会编译报错
1 先初始化一个空项目(npm init -y)目录结构: 2 | 3 |——dist // dist文件用来存放打包后的文件 4 |——src 5 | |——index.js 6 | |——index.html 7 |——package.json
index.html中代码
1 <body> 2 <ul> 3 <li>这是第1个li标签</li> 4 <li>这是第2个li标签</li> 5 <li>这是第3个li标签</li> 6 <li>这是第4个li标签</li> 7 <li>这是第5个li标签</li> 8 <li>这是第6个li标签</li> 9 <li>这是第7个li标签</li> 10 </ul> 11 </body> 12 13 <script src="./index.js"></script>
index.js中代码
1 // 先需要安装jQuery,npm i -S jquery 2 import $ from "jquery"; 3 4 $(function () { 5 $("li:even").css("backgroundColor", "blue"); 6 $("li:odd").css("backgroundColor", "pink"); 7 });
二、webpack五个核心概念
这五个核心概念属于webpack的配置
1、entry
本项目应该使用哪个模块来作为构建其内部依赖图的开始(指定打包入口文件),打包入口文件默认为src/index.js
2、output
在哪里输出它所创建的 bundles,以及如何命名这些文件,打包输出文件默认值为dist/main.js
3、loader
loader让webpack能够去处理那些非js文件(webpack自身只理解js)
4、plugins
-
插件可以用于执行范围更广的任务
-
插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量
5、mode
通过选择development和production中的一个,来设置mode参数,可以启用相应模式下的webpack内置的变化
三、webpack安装
webpack是运行在node环境中的,需要Node>= 8.10和npm>=5.6的版本支持。
-
在项目中安装webpack的方式如下:
1 npm i -D webpack@4.44.2 webpack-cli@3.3.12 2 # 由于目前这个2个工具大版本号已经升级,并且不兼容后续使用的工具,所以这边使用指定的低版本号
-
安装好后可以通过先前提及过的
npx
命令来检查webpack的版本以确定是否安装成功:1 npx webpack --version
-
在package.json文件中的
scripts
节点配置webpack运行脚本命令(指令名称自行决定): -
此时在终端运行
npm run compact
对之前隔行换色
项目进行打包1 npm run compact
-
打包完毕后会在当前项目目录下产生
dist
目录,里面会包含一个main.js
文件,修改src/index.html
文件,将原先的JavaScript文件引入修改为打包好的文件:1 <!-- <script src="./index.js"></script> --> 2 <script src="../dist/main.js"></script>
-
最终效果如下
四、webpack基本配置文件
1、单配置文件
在项目根目录下面创建一个webpack.config.js文件,webpack运行环境为nodejs,所以文件中的模块化规范为commonjs写法
该配置文件创建后会被webpack在打包时自动使用,因此文件名不能写错
1 const path = require("path"); 2 3 module.exports = { 4 // 打包模式 development | production 5 mode: "development", 6 // 项目入口 7 entry: "./src/index.js", 8 // 项目出口 9 output: { 10 path: path.resolve(__dirname, "dist"), 11 // [name]默认的名称为main(如果需要分目录,可以在名字前加文件夹名字) 12 filename: "[name].js", 13 }, 14 };
2、多配置文件
-
在项目根目录创建一个config目录,用于存放多配置文件
-
这两个文件不像webpack.config.js一样会被webpack自动引用,因此需要在package.json中分别进行引入指定
-
后续需要将项目打包成开发环境执行命令:
npm run compact:dev
-
如果需要将项目打包成生产环境执行命令:
npm run compact:pro
五、webpack配置自动打包
-
安装
webpack-dev-server
1 npm i -D webpack-dev-server@3.11.0
-
修改package.json配置命令
-
执行自定义打包命令
1 npm run compact
-
该命令执行后会处于实时监听状态
-
会产生并运行一个临时服务器供我们预览,地址是:
http://127.0.0.1:8080
-
打包生成的输出文件会托管在项目根下(注意index.html中引入文件路径是否正确),但文件是虚拟的,无法看见,并不会产生
dist
目录,如果要得到打包的目录,还得运行之前的打包命令
-
-
此外,webpack-dev-server自动打包操作还支持添加一些常见的配置选项
-
--open:打包完毕后自动运行浏览器
-
--host:配置打包服务器访问的地址
-
--port:配置打包服务器访问的端口
1 "scripts": { 2 "compact": "webpack-dev-server --open --host 127.0.0.1 --port 8888" 3 }
-
六、webpack配置默认预览页
在上节中需要在http://127.0.0.1:8080点击src文件才能预览页面效果,比较麻烦,可以通过配置进一步简化
-
安装一个扩展模块
1 npm i -D html-webpack-plugin
-
然后修改webpack的配置文件(注意使用的是单配置文件还是多配置文件,到对应的文件中修改),增加以下配置
1 const HtmlWebpackPlugin = require("html-webpack-plugin"); 2 3 module.exports = { 4 // .... 5 plugins: [ 6 new HtmlWebpackPlugin({ 7 template: "./src/index.html", 8 title: "jQuery的隔行变色" 9 }), 10 ], 11 }
上面代码的title配置项的作用是替换index.html中head标签里默认显示的标题,这个值可以在模板中通过特定的标记输出:
1 <title><%= htmlWebpackPlugin.options.title %></title>
-
注:修改配置文件后需要重新启动打包服务;使用该插件后,除了我们手动引入的main.js,还会自动在视图中引入打包好的main.js
七、webpack加载器
在实际开发中,webpack只能打包处理以.js
为后缀的模块,其他后缀的模块webpack处理不了,需要使用loader加载器才能正常打包
1、处理css文件
没有安装css加载器的时候打包包含css文件的项目会报错
-
安装css加载器:
1 npm i -D style-loader css-loader
-
安装好加载器后需要在配置文件
webpack.config.js(例:单文件)
中进行配置1 module: { 2 rules: [ 3 {test: /\.css$/, use: ["style-loader", "css-loader"]} 4 ] 5 }
-
在写加载器use的时候,需要注意
-
use数组中指定的加载器顺序是固定的
-
多个加载器调用的顺序是:从后往前、从下往上(倒序)
-
2、处理less文件
-
安装less加载器:
1 npm i -D less-loader less
-
安装好加载器后需要在配置文件
webpack.config.js(例:单文件)
中进行配置1 module: { 2 rules: [ 3 {test: /\.less$/, use: ["style-loader", "css-loader", "less-loader"]} 4 ] 5 }
3、处理scss文件
-
安装scss加载器
1 npm i -D sass-loader node-sass
-
安装好加载器后需要在配置文件
webpack.config.js(例:单文件)
中进行配置1 module: { 2 rules: [ 3 {test: /\.scss$/, use: ["style-loader", "css-loader", "sass-loader"]} 4 ] 5 }
4、自动添加css兼容前缀
部分样式需要添加特定浏览器前缀才会被浏览器支持
-
安装对应加载器
1 npm i -D postcss-loader autoprefixer
-
随后在项目根目录下创建postcss配置文件
postcss.config.js
1 const autoprefixer = require("autoprefixer") 2 3 module.exports = { 4 plugins: [autoprefixer] 5 }
-
在
webpack.config.js
文件中加入针对前缀兼容的打包规则:1 module: { 2 rules: [ 3 {test: /\.css$/, use: ["style-loader", "css-loader", "postcss-loader"]} 4 ] 5 }
在IE浏览器下,打包产生的代码可能无法运行看到效果,如果出现SCRIPT5009: “Promise”未定义
的报错,要先安装babel-polyfill
1 npm i -D babel-polyfill
之后修改webpack的打包入口配置:
1 entry: ["babel-polyfill", "./src/index.js"]
5、处理图片和字体
-
安装
1 npm i -D url-loader file-loader
-
安装好加载器后需要在配置文件
webpack.config.js(例:单文件)
中进行配置1 module: { 2 rules: [ 3 { 4 test: /\.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/, 5 use: "url-loader?limit=16940" 6 } 7 ] 8 }
注意:?之后是loader的参数项,limit参数用于指定图片的大小,单位为字节,小于limit指定的大小,会被转化成base64编码形式
如果图片被转化成base64编码的形式,通过打包得到的
dist
目录中就没有对应的图片文件,如果没有被转化成base64编码的形式,打包得到的文件中会有对应的文件
6、处理js文件中的高级语法
像工厂模式、构造函数这些属于js高级原发,使用babel完成js兼容处理
-
安装babel转换器相关包:
1 npm i -D babel-loader @babel/core @babel/runtime
-
再去安装babel语法插件相关的包:
1 npm i -D @babel/preset-env @babel/plugin-transform-runtime @babel/plugin-proposal-class-properties
-
再去根目录下创建babel配置文件
babel.config.js
并初始化:1 module.exports = { 2 presets: ["@babel/preset-env"], 3 plugins: ["@babel/plugin-transform-runtime","@babel/plugin-proposal-class-properties"] 4 }
-
最后在webpack的配置文件中设置打包规则:
1 module: { 2 rules: [ 3 { 4 test: /\.js$/, 5 use: "babel-loader", 6 exclude: /node_modules/ 7 } 8 ] 9 }
八、webpack其他细节
为了观察打包的细节,使用非自动打包
1、entry多入口
前面使用webpack打包的方式是针对SPA形式的页面,如果项目中有多个页面就不适用了,此时需要将webpack的入口配置成多入口形式
例如:需要将index.html
和login.html
两个页面同时进行打包,entry改成如下形式
1 entry: { 2 main: "./src/index.js", 3 login: "./src/login.js", 4 // .... 5 }
多文件/多入口打包的方式可能出现的问题:一个大型项目,js等文件会以功能模块进行分目录存储,但是即使多入口路径不存在冲突,由于output
输出是统一的,那么就可能出现文件同名而导致文件覆盖的情况
因此,如果是多入口文件的打包,对于输出文件的输出要做一些处理:
1 output: { 2 // join或resolve均可 3 path: path.join(__dirname, "dist"), 4 // `:N`中的N为数字,取值范围为1-20,加上表示指定Hash的长度(可选),不加默认为20位hash值 5 filename: "[name]-[contentHash:N].js", 6 },
2、路径别名与默认后缀
Vue中可以使用@符号表示src目录,使用起来比较轻松,但是再webpack中使用会报错,需要进行配置
配置方法:修改webpack配置文件,在配置选项中添加resolve选项,增加配置别名
1 resolve: { 2 // 配置解析模块路径别名:优点简写路径,缺点路径没有提示 3 alias: { 4 // 定义一个@,可在import引入时使用 5 "@": path.join(__dirname, "src"), 6 }, 7 // 设置可以忽略不写的后缀 8 extensions: [".js", ".json", ".vue"], 9 }
3、忽略打包
webpaack中的externals
选项提供了不从bundle捆绑中使用依赖的方式。
在开发项目时,有些外部模块通过CDN链接
使用script
标签引入到页面中可能要比通过打包使用更加方便,例如jQuery库。此时就可以使用externals
忽略打包的方式去指定哪些库不需要webpack进行打包。
例如,需要忽略对jQuery的打包,则可以写成:
1 externals: { 2 jquery: 'jQuery', 3 // ..... 4 }
注意:不被webpack打包的外部依赖,后期依旧可以通过以下方式使用
-
script
标签引入(推荐) -
import导入
-
import ... from "xxx"
-
import { a, b, c } from "xxx"
-
4、打包处理vue文件
-
在项目中安装vue
1 npm i -S vue
-
创建vue文件:
/src/vue/demo.vue
1 <template> 2 <div> 3 {{ msg }} 4 </div> 5 </template> 6 7 <script> 8 export default { 9 data() { 10 return { 11 msg: "Hello World", 12 }; 13 }, 14 }; 15 </script>
-
创建vue入口文件:
/src/vue/app.js
1 import Vue from "vue"; 2 import App from "@/vue/demo.vue"; 3 4 new Vue({ 5 el: '#app', 6 render: h => h(App) 7 })
-
在打包入口指定vue文件入口
1 entry: { 2 demo: "./src/vue/app.js", 3 // ..... 4 },
-
进行打包会出错,安装loader
1 npm i -D vue-loader vue-template-compiler
-
在
webpack.config.js
中配置1 const VueLoaderPlugin = require("vue-loader/lib/plugin"); 2 3 module.exports = { 4 plugins: [ 5 new VueLoaderPlugin(), 6 ], 7 module: { 8 rules: [ 9 { 10 test: /\.vue$/, 11 loader: "vue-loader", 12 }, 13 ] 14 } 15 }
九、配置文件
1、postcss.config.js
自动添加css兼容前缀(参考第七节第4小节)
1 const autoprefixer = require("autoprefixer") 2 3 module.exports = { 4 plugins: [autoprefixer] 5 }
2、babel.config.js
处理js文件中的高级语法(参考第七节第6小节)
1 module.exports = { 2 presets: ["@babel/preset-env"], 3 plugins: ["@babel/plugin-transform-runtime","@babel/plugin-proposal-class-properties"] 4 }
3、webpack.config.js
1 // 默认单文件配置 2 const path = require('path'); 3 // 配置默认预览页 4 const htmlWebpackPlugin = require('html-webpack-plugin'); 5 // 引入vue打包插件 6 const VueLoaderPlugin = require('vue-loader/lib/plugin'); 7 8 module.exports = { 9 // 使用的打包模式:development | production 10 mode: "development", 11 12 // 打包入口 13 entry: { 14 main: ["babel-polyfill", "./src/index.js"], 15 login: "./src/login.js", 16 demo: "./src/vue/app.js" 17 }, 18 19 // 输出文件位置 20 output: { 21 path: path.join(__dirname, 'dist'), 22 filename: '[name]-[contentHash:10].js' 23 }, 24 plugins: [ 25 new htmlWebpackPlugin({ 26 // 指定默认视图位置 27 template: './src/index.html', 28 title: 'jquery的隔行换色' 29 }), 30 new VueLoaderPlugin(), 31 ], 32 module: { 33 rules: [ 34 { test: /\.css$/, use: ["style-loader", "css-loader", "postcss-loader"] }, 35 { test: /\.less$/, use: ["style-loader", "css-loader", "less-loader"] }, 36 { test: /\.scss$/, use: ["style-loader", "css-loader", "sass-loader"] }, 37 { 38 test: /\.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/, 39 use: "url-loader?limit=16940" 40 }, 41 { 42 test: /\.js$/, 43 use: "babel-loader", 44 exclude: /node_modules/ 45 }, 46 { 47 test: /\.vue$/, 48 use: "vue-loader", 49 }, 50 ], 51 }, 52 resolve: { 53 // 起路径别名 54 alias: { 55 "@": path.join(__dirname, "src"), 56 "$css": path.join(__dirname,"src/css") 57 }, 58 // 默认后缀可以省略 59 extensions: [".js", ".json", ".vue"], 60 }, 61 // 忽略打包配置 62 externals: { 63 // jquery: 'jQuery', 64 } 65 }