习惯用脚手架的你, 了解Webpack这些知识点吗?
大概准备春招两个月了, 也没找到坑位埋自己, 来看看webpack
webpack
官网: www.webpackjs.com
对于前端的大兄弟来说, 每天在前端摸爬滚打, 各方征战, 那对于webpack肯定再熟悉不过了
所以说这篇文章适合给像我们这样的后端的同胞看着玩,(一说前端不是想用BootStrap就想用其他前端框架的UI组件库, 要不就是vue的脚手架) , 那对于浪迹各大vue react组件库的你, 对于喜欢用脚手架构建项目的你, 对于喜欢一键打包项目的你, 真的了解webpack各种目录和默认配置吗?
webpack的核心概念:
- 入口: 从哪里开始打包
- 出口: 打包的结果输出到哪里去
- loader: 我们通过npm给webpack安装上不同的loader, webpack就能处理不同格式的文件, 用于处理图片等静态资源的loader, 处理css的loader, 处理less的loader, 用于适配各种浏览器的loader等等
- 插件: 作用于整个打包过程, 比如用于本件拷贝的插件, 用于生成html的插件, 用于处理css的插件
搭建一个空的项目
通过这个小案例你将了解:
- 局部安装webpack-cli的命令是什么 ?
- 如何在新项目中使用局部安装的webpack ?
- webpack的默认启动目录, 启动文件在哪里 ? 叫什么 ?
- 什么是mode? (development production)
- 有哪些build mode , 这些mode有何区别 ?
继续:
命令: npm init
创建一个空项目
执行完成后, 会为我们生成一个packetage.json文件
然后安装webpack 包管理工具命令: npm i webpack-cli -D
注意点:上面的安装命令是局部安装命令, 如果我们进入这个项目中, 使用npm run build
命令尝试将这个项目打包时, 会报错 说 missing script : build
解决方法: 在package.json
的script部分中加入下面的配置 后, 再使用 npm run build
命令时, 会自动使用我们在局部安装的这个命令
--mode 指定在什么环境下打包, 上面的 production 就是说打包后在生产环境下使用, 和development最直接的不同点就是 前者会将main.js 压缩
继续执行npm run build
命令: 会遇到新的错误, 说解析不到 src目录, 原因是webpack找到不到入口目录
默认的, webpack的入口会去找 src/index.js
我们在根目录下将这个目录创建出来, 再次执行npm run build
即可打包成功, 打包的结果: /dist/main.js , 会将项目中依赖的js文件, 打包成一个js文件
npm run xxx ,命令中的xxx就是上图中的srcipt中定义的 比如npm run dev , npm run build , npm run start , npm run test
webpack的配置文件
看完这本小节你将了解:
- webpack默认的配置文件叫什么 ?
- webpack默认的配置文件在哪里 ?
- 如何修改webpack默认配置文件所在的路径和名称 ?
- webpack的入口js文件可以修改吗? 如何修改 ?
- webpack的配置文件中output目录及文件可以修改吗? 如何修改 ?
- output输出的目标文件默认叫什么名? 可以修改吗?
- webpack有哪些hash函数可以使用 ?
ok, 继续:
- 有哪些默认的配置?
webpack.config.js, 默认的webpack会去根目录中寻找他, (如过我们把它放在自定义的目录中, webpack是找不到它的)
但是可以在 package.json中去修改这个默认的配置, 如下: 添加--config
参数
- 能添加哪些自定义的配置?
webpack.config.js 配置文件的作用的对外暴露node.js的配置脚本, 看下图, 可以知道, webpack.config.js中对应的就是webpack对应的各个模块的
参照这个连接: https://www.webpackjs.com/concepts/configuration/
用大白话说, webpack.config.js 可以告诉webpack打包的mode, 是否需要压缩, 入口js文件在哪里, 打包结果输出到什么目录, 输出结果叫什么, 等等
var path = require('path');
module.exports = {
mode: 'development', // 指定打包后在什么环境下使用
entry: './src/index.js', // 指定入口js文件, todo 可以在这里修改入口js文件
output: {
path: path.resolve(__dirname, 'dist'), // 打包后的文件所在的目录名
//filename: 'foo.bundle.js' // 打包后生成的文件名, 默认是main.js
// hash值是通过入口目录中的入口js算出来的, 一旦js改变, 每次build的结果的hash值
//filename: '[name].[hash].js' // 生成的文件名: main.e9bsajdoahsds.js
//filename: '[name].[hash:6].js' // 生成的文件名: main.6位长度hash值.js
filename: '[name].[chunkHash:6].js' // 生成的文件名: main.6位长度hash值.js 且共存多个模块时, 只有那个发生变动的入口js对应生成的 output文件名中的js哈希值才会改变
// 第三种hash contenthash ,是根据文件的内容计算出来的hash
}
};
- webpack的三种hash值
- hash: 它是工程级别的, 即修改工程中任何一个文件, 整个工程的文件缓存都会失效, 打包出来的文件的hash值都会发生改变, 缺点: 如果项目存在多个入口, 势必针对每一个入口js文件都打包出来一个带有hash值的结果文件, 虽然是两个不同的入口, 但是属于一个工程, 所有多个目标文件的hash值都会改变
- chunkHash: 它解决了hash的缺点带来的不足条件, 还是同一个项目,多个入口js的情况, 使用chunkHash模式, 然后修改一个入口js的内容, 打包出来的结果文件中, 只有被修改了的那个js的hash改变;
- contentHash: 根据文件的内容计算hash
打包后自动生成html
学完本节你将了解
- 如何让webpack打包出一个单页index.html
- 如何让webpack基于我们自己提供的html页面生成 index.html
参考链接: https://www.npmjs.com/package/html-webpack-plugin
默认的, webpack会将项目中依赖的js文件打包称一个js文件输出到 / dist / 目录中, 但是不会为我们生成html文件, 这时候我们需要手动的将生成的js文件引入到我们自己的index.html文件中, 这样整挺麻烦的
所有, 一般我们会这么搞, 把自己的index.html文件放在/public/index.html中, 然后安装webpack的插件, 让这个插件替我们完成上面的那个复杂的过程, 如下
安装命令:
npm i --save-dev html-webpack-plugin
参考: webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: 'index.js',
output: {
path: __dirname + '/dist',
filename: 'index_bundle.js'
},
// 着重看一下这个plugin模块
plugins: [
new HtmlWebpackPlugin(), // Generates default index.html
new HtmlWebpackPlugin({ // Also generate a test.html
filename: 'test.html',
// 允许用户自定义一个html模板, webpack会在这个模板上累加上自己生成的js
template: 'src/assets/test.html'
})
]
}
引入CSS
看完本节你将了解:
- 两种方式让webpack替我们导入css文件
参考链接: https://www.npmjs.com/package/css-loader
- 第一种方式:
安装loader插件命令
npm i style-loader -D
npm install --save-dev css-loader
参考配置文件 : 通过一个rules来控制这个过程, 通过正则匹配到css, 然后对这些匹配到的文件使用 style-loader css-loader , 执行的顺序的 后面的css-loader比style-loader先执行
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
],
},
};
通过如下方式将css引入
此时再执行 npm run build
可以完成构建工作
问题来了, 通过这种方式导入进来的css文件在哪里呢?
通过查看html源码可见, 构建出来的源码被放在head标签中
- 第二种引入css文件的方式, 将css导入进来, 并提取成一个独立的文件, 并自动插入到html中
参考链接: https://www.npmjs.com/package/mini-css-extract-plugin
安装命令:
npm install --save-dev mini-css-extract-plugin
参考webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
// 在plugins部分new出来
plugins: [
new MiniCssExtractPlugin(
{
filename: '[name].[chunkHash:8].css'
}
)],
module: {
rules: [
{
test: /\.css$/i,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
esModule: true,
},
},
'css-loader',
],
},
],
},
};
这种方式生成结果如下:
很明显: css被添加在head标签中, script添加在index.html末尾
小技巧, 如果想让生成的文件呈现下面的样子:
可以在webpack.config.js文件中, 使用下面的方式为文件命名
new MiniCssExtractPlugin(
{
filename: 'css/[name].[chunkHash:8].css'
}
)
CSS预处理
参考链接: https://www.npmjs.com/package/less-loader
目的是处理less, 将less转换成css
安装 less 和 less-loader
npm install less less-loader --save-dev
在webpack.config.js中添加less的解析规则
loader的第二种写法
{
test: /\.less$/i,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
// 'less-loader',
{
loader: "less-loader",
options:{
}
}
],
}
自动添加CSS前缀
看完本节你将了解
- 啥是css3前缀
- 为啥要加前缀
- 怎么通过webpack添加前缀
**那为啥要添加前缀呢? **
因为在CSS标准未被确定之前, 市面上的不同浏览器使用自己私有的前缀却分不同的CSS样式, 当标准确定之后, 各大浏览器不再使用这些前缀, 目前很多私有的前缀都可以不再写了, 但是为了兼容, 可以仍然使用前缀逐渐过度
常见的浏览器的前缀如:
- Chrome谷歌浏览器: -webkit-
- Safari苹果浏览器: -webkit-
- FireFox 火狐: -moz-
- IE: -ms-
- Opera 欧朋浏览器: -O-
例:
#example{
-webkit-outline: none;
-moz-outline: none;
-ms-outline: none;
-o-outline: none;
-khtml-outline: none;
outline: none;
}
如何配置webpack, 自动添加浏览器css3前缀
参考链接: https://www.npmjs.com/package/autoprefixer
安装命令:
npm i postcss-loader autoprefixer -D
第二步: 在项目的根目录下创建 postcss.config.js 配置文件
postcss的npm包参考链接: https://www.npmjs.com/package/postcss
module.exports = {
plugins: [
// 他需要下面的插件 autoprefixer
require('autoprefixer'),
]
}
第三步: 在webpack.config.js配置文件中添加指定的postcss-loader, 注意把他的添加顺序, 放在靠前的位置
第四步: 在package.json配置文件中添加 browerslist相关配置, 可以针对不同浏览器做出更详细的配置
参考链接: https://www.npmjs.com/package/browserslist
实例:
"browserslist": [
"defaults",
"not IE 11",
"not IE_Mob 11",
"maintained node versions",
]
并不是浏览器包含的越多越好, 比如说想用ES5的话, IE的版本至少要大于等于8
处理资源文件
看完本节, 你将了解:
- 三种处理资源文件的方式
- 第一种处理方式 file-loader
使用file-loader处理资源文件, 参考链接 <https://www.npmjs.com/package/file-loader >
安装命令:
npm install file-loader --save-dev
参照上面链接中的示例配置, 为webpack.config.js中添加file-loader相关的模块
示例:
rules: [
{
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: 'file-loader',
options:{
// 指定webpack打包后, 输出的路径
name: 'static/images/[name].[ext]',
// 这个publicPath规定的路径, 就是webpack运行项目后, 所有的资源文件url的最前面的公共部分
publicPath: '/',
}
},
],
}
]
注意点: 如果不添加publicPath的话, 将出现下面的问题
- 第二种处理方式
参考链接: https://www.npmjs.com/package/url-loader
url-loader的优点, 会针对不同图片做不同的压缩
安装命令
npm install url-loader --save-dev
同样是在webpack.config.js中添加配置
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
// url-loader和file-loader的工作原理相似, 当资源的大小小于limit指定的值时, 资源将被替换成base64编码的数据植入html或者 css中
limit: 80,
name: 'static/images/[name].[ext]',
// 这个publicPath规定的路径, 就是webpack运行项目后, 所有的资源文件url的最前面的公共部分
publicPath: '/',
},
},
],
}
url-loader的特点如下:
- 当资源size < limit值时, 将使用base64对资源进行加密处理
- 当资源size > limit值时, 和file-loader相似, 将图片本身输出到指定的目录中
- 第三种处理方式
比如项目中引用了字体文件, 直接写死在index.html模板中, 而不需要使用file-loader或者url-loader进行压缩之类webpack的处理和生成的操作, 那么可以使用下面的插件, 直接进行文件的copy
参考链接: https://www.npmjs.com/package/copy-webpack-plugin
命令:
npm install url-loader --save-dev
参考webpack.config.js如下:
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
plugins: [
new CopyPlugin([
{ // 将项目根路径下的static目录中的内容, 拷贝到dist/static/images中
from: path.resolve(process.cwd(),'static/'),
to: path.resolve(process.cwd(),'dist/static/images中')
},
]),
],
};
添加Babel-loader
为什么要使用babel-loader?
我们都是到, 浏览器只认识html css 原生js , 后续js发展的很快, ES5 ES6出世了, 但是不少浏览器根本不支持ES6的语法, 比如 import export 对象/函数 等等
如何使用?
参考链接: https://www.npmjs.com/package/babel-loader
安装命令:
npm install -D babel-loader @babel/core @babel/preset-env webpack
示例:
rules: [
// the 'transform-runtime' plugin tells Babel to
// require the runtime instead of inlining it.
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-transform-runtime']
}
}
}
]
webpack让前端项目独立占用一个端口运行
通过这小节你将知道:
- webpack 通过什么让前端项目独立运行
- 如何安装这个插件
- 如何配置进webpack, 让webpack使用它
- 在那个配置文件中对devs-server进行更多的配置
参考连接: https://www.npmjs.com/package/webpack-dev-server
安装命令:
npm install webpack-dev-server --save-dev
修改npm的配置文件, 添加dev选项
这也就是为啥, 通过脚手架构建的开发环境, 能npm run dev
运行起来
并且, 项目运行起来后, 我们做出的任何修改, 都会热加载进来, 时时更新, 无须重启
在webpack.config.js中添加devServer模块
如:
一般在开发时. 这个配置肯定是需要定制的, 如果在这里模拟前后端联调, 就在这个模块配置mock数据的地址
devServer: {
change xxx-api/login => mock/login
detail: https://cli.vuejs.org/config/#devserver-proxy
},
或者是真的在前后端联调, 因为端口不同将出现跨域, 在这里配置代理服务器的地址
// 参考: https://www.webpackjs.com/configuration/dev-server/#devserver-proxy
devServer: {
proxy: 'http://localhost:8089'
},
比如, 自动打开啊等等, 更多的配置 参考链接 https://www.webpackjs.com/configuration/dev-server/