前言
我相信不少朋友和我一样,刚开始学习 vue
的时候,都是用 vue-cli
创建的项目,vue-cli
确实是个好东西,让我们不需要关心 webpack
等一些繁杂的配置。 然后直接开始写业务代码。但这会造成我们过度依赖 vue-cli
,忽视了 webpack
的重要性,当遇到一些特殊场景时候,例如:vue 多入口的配置、优化项目的打包速度等等。便无从下手。
vue-cli
提供了修改webpack
配置的入口——vue.config.js
。即使你熟悉webpack
,但你不知道vue-cli
内部配置了什么,也很难下手。所以有些公司会选择自己手动搭建,自己配置了哪些东西,心里有数。便于维护。
所以无论如何,学好webpack
准没错啦 !
webpack 5
正式版是 2020-10
发布的,相信很多公司用的还是 webpack 4
。所以这篇文章就先介绍 webpack 4
。
安装时候注意依赖的版本,最好带上版本号,下面是依赖的版本。否则会出现不兼容的情况
"devDependencies": {
"autoprefixer": "^10.3.1",
"babel-loader": "^8.2.2",
"css-loader": "^5.2.7",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^4.5.2",
"less": "^3.5.0",
"less-loader": "^7.3.0",
"postcss-loader": "^4.3.0",
"style-loader": "^2.0.0",
"url-loader": "^4.1.1",
"vue-loader": "^15.9.6",
"vue-template-compiler": "^2.6.14",
"webpack": "^4.46.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.11.2",
},
"dependencies": {
"vue": "^2.6.14",
"vue-router": "^3.5.2",
"vuex": "^3.6.2"
}
续集:
文章 demo 已发送到 github 请自行下载,】「demo 包括了第二篇的文章内容,推荐看完第二篇」 —— 「demo」
看要是对你有帮助,麻烦点个赞~ 谢谢。
npm 初始化
在你的根目录上运行 npm init
,生成 package.json
npm init
安装 webpack
npm
默认安装的是最新版本的webpack
,所以要指定版本号。webpack 4
以上版本需要安装 webpack-cli
,也要指定版本。
npm i -D webpack@4.46.0 webpack-cli@3.3.11
测试 webpack 是否安装成功
我们通过简单打包方式测试 webpack
是否安装成功
在src
中创建一个 main.js
,随便写个console
。
//main.js
console.log('我只会 webpack 打包,你公司还要人吗?')
package.json 配置 npm 脚本命令
//实际项目中不建议在脚本命令上添加参数
"scripts": {
"build": "webpack src/main.js -o dist/bundle.js"
},
然后运行 npm run build
如果看到 dist
中生成了 bundle.js
就说明 OK了。你可以在 bundle.js
中找到 main.js
的内容
很多朋友会想到在 terminal(终端)
中直接运行不就行了,为什么还要配置 npm 脚本
?因为直接在 terminal
运行,用的是你全局安装的 webpack
版本,和你项目中的 webpack
有差异。如果你全局没有安装 webpack
那就会直接报错。
webpack 一些基本认知
loader
webpack
默认情况下只支持js、json
格式的文件。所以要把css、img、html、vue
等等这些文件转换成 js
,这样webpack
才能识别,这时候就要用到webpack
中的loader
,我们可以把loader
理解成转换器
;
plugin
webpack
在打包的过程中,会在特定的节点执行一些函数,类似 vue
一样生命周期函数。plugin
可以通过这些监听函数,执行一些webpack
本身之外操作。例如:压缩图片
、优化打包
等等
配置 webpack 支持 less「css 包含在里面」
安装 loader
为了便于维护,项目中往往会使用 css 预处理器 ——Sass、Less 或者 Stylus
,这里以Less
为例,其他的类似,请自行百度
style-loader
,把CSS
插入到DOM
中css-loader
, 解析CSS
文件中的@import
和url
,处理css-modules
把css
转换js
less-loader
,把less
转换成css
less
, 让项目支持less
npm install less@3.5.0 less-loader@7.3.0 css-loader@5.2.7 style-loader@2.0.0 --save-dev
配置 webpack.config.js
根目录新建 webpack.config.js
,这是 webpack
的配置文件
const path = require('path');
module.exports = {
mode: "development",
entry: "/src/main.js", //入口
output: {
path: path.join(__dirname, "./dist"), //打包输出路径,必须是绝对路径
filename: "bundle.js" //打包之后的 JS 名称
},
module: {
rules: [
// 处理 css
{
test: /\.(css)$/,
use: [
"style-loader",
"css-loader"
]
},
// 处理 less
{
test: /\.(less)$/,
use: [
"style-loader",
"css-loader",
"less-loader"
]
},
// 处理 less 和 css ,不推荐使用,文件为CSS 时,虽然也可以处理,但是速度会比较慢(css文件大的时候特别明显)。因为需要先经过 less-loader 的处理,多了个步骤
// {
// test: /\.(less|css)$/,
// use: [
// "style-loader",
// "css-loader",
// "less-loader"
// ]
// },
]
}
};
修改 npm 脚本
"scripts": {
"build": "webpack"
},
测试 less 是否生效
新建 index.less
, 随便在写点样式。
div {
width:100px;
height:100px;
background:red
}
在 main.js 中引入 less 文件,运行 npm run build
进行打包
import "./css/index.less"
在 dist
目录下新建一个 html
,并引入打包后的 bundle.js
, 看看样式是否生效。
<body>
<div>less样式生效</div>
<script src="./bundle.js"></script>
</body>
使用 html-webpack-plugin ,生成html,自动引入 bundle.js
大家应该注意到,vue-cli
时候项目打包的时候会自己在 dist
目录下生成一个html
文件,并引入bundle.js
,就是通过html-webpack-plugin
实现的。
安装 html-webpack-plugin
npm i html-webpack-plugin@4.5.2 -D
webpack.config.js 配置 HtmlwebpackPlugin
const HtmlwebpackPlugin = require('html-webpack-plugin')
plugins: [
new HtmlwebpackPlugin({
//配置 html 生成模版
template: path.join(__dirname, './src/index.html')
})
]
webpack-dev-server
我们平时开发项目,预览效果时,一般直接访问某个ip + 端口
进行调试的。webpack-dev-server
就是用来帮我们实现这个功能,它实际上是基于express「NodeJS框架」
来实现 web服务器
的功能。
注意:webpack-dev-server 打包之后的 html 和 bundle.js 是放在内存中的,目录里是看不到的,一般会配合 webpack 的热更新模块来使用
安装 webpack-dev-server
npm i webpack-dev-server@3.11.2
webpack.config.js 配置 devServer
devServer: {
contentBase: path.join(__dirname, "./dist"), //打包之后的目录
open: true, //打包完成自动打开浏览器预览
quiet: true, //隐藏在 terminal中显示打包信息
progress: true, //显示打包进度
port: 3000 //不指定端口会自动分配
},
package.json 添加 npm 脚本
serve
为新加的 npm 脚本 , 运行 npm run serve
就可以预览项目了
"scripts": {
"serve": "webpack-dev-server",
"build": "webpack"
},
HotModuleReplacementPlugin 热更新
HotModuleReplacementPlugin
是webpack
内置的模块,不需要额外安装,可以配合webpack-dev-server
实现热更新的功能
webpack.config.js 配置 devServer
const webpack = require("webpack")
devServer: {
hot: true, //开启热更新
clientLogLevel: 'none', //关闭浏览器控制台输出的热更新信息
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
测试热更新
在 main.js
里加个 console.log
在控制台能看到对应的信息就可以了
配置 webpack
支持打包 字体、图片等文件
安装 url-loader 和 file-loader
url-loader
解析为 url 并将文件复制到输出目录中, 还支持 base64
图片格式的转换
url-loader
把文件转成 bas64file-loader
把文件复制到指定的目录
npm i style-loader@2.0.0 url-loader@4.1.1 -D
配置 loader
rules: [
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192, //小于 8K ,用 url-loader 转成 base64 ,否则使用 file-loader 来处理文件
fallback: {
loader: 'file-loader',
options: {
name: '[name].[hash:8].[ext]',
outputPath: 'images/', //打包之后文件存放的路径, dist/images
// publicPath: 'assets/' // 拼接在url的目录,不设置默认使用 outputPath 的路径
}
// 路径也可以直接写在 name 上,和上面效果一致
// options: {
// name: 'images/[name].[hash:8].[ext]',
// }
},
}
}
]
},
// 媒体文件
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
fallback: {
loader: 'file-loader',
options: {
name: '[name].[hash:8].[ext]',
outputPath: 'media/',
}
},
}
}
]
},
//字体文件
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 1,
fallback: {
loader: 'file-loader',
options: {
name: '[name].[hash:8].[ext]',
outputPath: 'fonts/',
}
},
}
}
]
}
]
测试 loader 是否生效
在样式里加个背景图片,调整 limit
的阈值,查看是否有转换成 base64
,如果可以那就是说明url-loader
没有问题,要是在dist
里生成了images/xxx.xx
,就说明file-loader
生效了。
配置 webpack 支持 vue
安装依赖
vue
vue 官方依赖包vue-loader
解析.vue
文件vue-template-compiler
解析.vue
文件里面的template
,配合vue-loader
使用
安装 vue
npm i vue@2.6.14 -S
安装 loader
npm i vue-loader vue-template-compiler -D
webpack.config.js 配置 vue-loader
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module: {
rules: [
{
test: /\.vue$/,
use: [
{
loader: "vue-loader"
}
]
}
],
plugins: [
new VueLoaderPlugin()
]
}
测试 vue 是否可以正常编译
index.html
添加 vue
挂载的 DOM 元素 (#app)
<body>
<div id="app"></div>
</body>
新建 App.vue
,写一个简单的双向绑定例子
<template>
<div>
<div class="text">{{ text }}</div>
<input type="text" v-model="text" />
</div>
</template>
<script>
export default {
data() {
return {
text: '不是阿怪的阿怪'
}
},
methods: {}
}
</script>
<style lang="less" scoped>
.text {
color: red;
}
</style>
main.js
导入 vue
并挂载
import Vue from "vue"
import App from "./App.vue";
new Vue({
render: (h) => h(App)
}).$mount("#app")
能编译过基本就没有问题了,测试一下双向绑定正常就 OK
Vue Router
安装 vue-router
npm i vue-router@3.5.2 -S
新增 views/Home.vue
<template >
<div>
<div>Vue Router 搞定</div>
</div>
</template>
新建 router/index.js
import VueRouter from "vue-router"
import Vue from "vue"
Vue.use(VueRouter)
const routes = [{
path: '/',
name: 'Home',
component: () => import('../views/Home.vue')
}]
const router = new VueRouter({
routes
})
export default router
App.vue
加上 <router-view/>
<template>
<div>
<router-view />
</div>
</template>
main.js
导入 router/index.js
, 并使用
import Vue from "vue"
import App from "./App.vue";
import router from "./router/index"; //关键代码
new Vue({
router, //关键代码
render: (h) => h(App)
}).$mount("#app")
运行预览效果,能看到 Vue Router 搞定
几个字就证明 vue-router
OK 了
Vuex
安装 vuex
npm i vuex@3.6.2 -S
新建 store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
text: '默认值'
}
const getters = {
getText(state) {
return state.text
}
}
const actions = {
setText: ({ commit }, text) => {
return commit('setText', text)
}
}
const mutations = {
setText: (state, text) => {
state.text = text
}
}
export default new Vuex.Store({
state,
actions,
mutations,
getters
})
main.js
导入store/index.js
,并使用
import Vue from "vue"
import App from "./App.vue";
import router from "./router/index";
import store from "./store"; //关键代码
new Vue({
store, //关键代码
router,
render: (h) => h(App)
}).$mount("#app")
Home.vue
中使用 vuex
<template >
<div>
<div>'vuex-state:'{{ text }}</div>
<div>'vuex-getter:'{{ getText }}</div>
<button @click="setText(123)">修改state的值</button>
</div>
</template>
<script>
import { mapGetters, mapState, mapActions } from "vuex"
export default {
data() {
return {
}
},
computed: {
...mapState(['text']),
...mapGetters(['getText'])
},
methods: {
...mapActions(['setText'])
}
}
</script>
预览效果,能看到默认值和可以修改值就证明 vuex
OK了
ES6+ 新特性兼容
安装依赖
npm i @babel/core@7.4.4 @babel/preset-env babel-loader core-js@3
@babel/core
babel
babel
核心包@babel/preset-env
集成bebal
一些可选方案,可以通过修改特定的参数来使用不同预设babel-loader
ES6+
转ES5
core-js
让不支持ES6+ API
的浏览器支持新API
。
配置 webpack.config.js
{
test: /\.js$/,
exclude: /node_modules/,
use: ["babel-loader"]
},
配置 .babelrc
根目录新建 .babelrc
文件,babel-loader
会读取里面的配置
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": 3,
"modules": false
}
]
]
}
CSS 不同浏览器兼容性
安装依赖
npm i postcss-loader@4.3.0 autoprefixer@10.3.1 -D
配置 webpack.config.js
{
test: /\.(css)$/,
use: [
"style-loader",
"css-loader",
"postcss-loader" //关键代码
]
},
{
test: /\.(less)$/,
use: [
"style-loader",
"css-loader",
"less-loader",
"postcss-loader",//关键代码
]
},
配置 postcss.config.js
根目录新建 postcss.config.js
,这postcss-loader
的配置文件
module.exports = {
plugins: {
autoprefixer: {}
}
}
配置 package.json
browserslist
主要配置需要兼容的浏览器版本,和 package.json
的 devDependencies
同级
"browserslist": [
"defaults",
"not ie <= 8",
"last 2 versions",
"> 1%",
"iOS >= 7",
"Android >= 4.0"
],
结尾
其实这里 vue 最基本的开发环境已经搭建完成了,但不代表这个项目足够完善了。例如:ES6+
语法转 ES5
;CSS
不同浏览器兼容性;区分开发环境
和生产环境
;还有一些优化的东西等等。篇幅原因就先写到这里。下一篇文章会续上
续集:
预告:
- webpack 5 搭建 vue 开发环境
文章 demo 已发送到 github 请自行下载,】「demo 包括了第二篇的文章内容,推荐看完第二篇」 —— 「demo」
要是对你有帮助,麻烦点个赞再走~ 谢谢。