前言
我相信不少朋友和我一样,刚开始学习 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转换jsless-loader,把less转换成cssless, 让项目支持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
安装依赖
vuevue 官方依赖包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/corebabelbabel核心包@babel/preset-env集成bebal一些可选方案,可以通过修改特定的参数来使用不同预设babel-loaderES6+转ES5core-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」
要是对你有帮助,麻烦点个赞再走~ 谢谢。