前言
今天的内容是如何从零搭建基于Webpack4的Vue前端脚手架,如有问题,欢迎来交流啊!
整个过程大致分为以下几个步骤:
- 搭建cvue-cli v1.0,就是一个最基本的架子,目标是可以成功本地运行和打包出文件。
2.搭建cvue-cli v2.0,把vue以及less什么的都安上,目标是运行后可以看到类似官方脚手架那样的页面。
3.搭建cvue-cli v3.0,最后在做一些优化工作,css该分离的分离,文件该压缩的压缩
注意:如需要,欢迎转载,但请注明转载文章出处 \o(^o^)o
正文
搭建cvue-cli v1.0
1.初始化项目
npm init -y
2.初始化项目的目录结构,结构如下:
3.修改package.json文件
{
"name": "cvue-cli",
"version": "1.0.0",
"description": "",
"private": true,
"scripts": {
"dev": "webpack --config build/webpack.base.config.js --mode development",
"build": "webpack --config build/webpack.base.config.js --mode production"
},
"keywords": [],
"author": "",
"license": "ISC"
}
- 配置webpack.base.config.js
// 先安装几个辅助插件
npm install --save-dev clean-webpack-plugin html-webpack-plugin webpack webpack-cli
const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugins = require('html-webpack-plugin')
module.exports = {
// 入口js路径,注意这里是./而不是../,下面HtmlWebpackPlugins的template属性也一样,我理解的是这里的路径都是相对于项目根目录
entry: './src/main.js',
// 配置编译文件输出路径
output: {
// 以原始文件名的输出文件名
filename: '[name].js',
path: path.resolve(__dirname, '../dist')
},
plugins: [
// 自动清空dist文件夹
new CleanWebpackPlugin(),
// 设置html模板生成路径
new HtmlWebpackPlugins({
filename: 'index.html', // 输出的html文件名,默认index.html
template: './public/index.html', // html模板路径,注意这里也是./而不是../
chunks: ['main'] // 指定在html自动引入的js打包文件
})
]
}
- 修改main.js文件
document.write('hello cvue-cli!')
- 运行npm run build打包编译文件,打包完的目录结构如下
浏览器打开index.html文件,页面中出现 “hello cvue-cli!”,恭喜你成功地迈出了第一步,下面再接再厉!
- 下面搭建开发环境的热监测服务器
npm install --save-dev webpack-dev-server
- 修改package.json中的dev命令
"dev": "webpack-dev-server --config build/webpack.base.config.js --open --mode development",
9.修改webpack.base.config.js文件
// 添加如下内容
devServer: {
contentBase: './dist', //指定需要提供给本地服务的内容的路径,默认加载index.html文件,可根据需要修改
port: 8080, // 端口设置,默认8080
hot: true // 开启热更新,浏览器自动刷新
}
- 将webpack配置进行分离,分为本地开发环境和生产环境
// 首先安装插件
npm install --save-dev webpack-merge
webpack.base.config.js保留如下内容(注意:这里修改了js的打包输出路径):
const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugins = require('html-webpack-plugin')
module.exports = {
// 入口js路径,注意这里是./而不是../,下面HtmlWebpackPlugins的template属性也一样,我理解的是这里的路径都是相对于项目根目录
entry: './src/main.js',
// 配置编译文件输出路径
output: {
// 以原始文件名的输出文件名
filename: 'js/[name].js',
path: path.resolve(__dirname, '../dist')
},
plugins: [
// 自动清空dist文件夹
new CleanWebpackPlugin(),
// 设置html模板生成路径
new HtmlWebpackPlugins({
filename: 'index.html', // 输出的html文件名,默认index.html
template: './public/index.html', // html模板路径,注意这里也是./而不是../
chunks: ['main'] // 指定在html自动引入的js打包文件
})
]
}
webpack.dev.config.js修改为如下内容:
const merge = require('webpack-merge')
const baseConfig = require('./webpack.base.config')
module.exports = merge(baseConfig, {
devServer: {
contentBase: './dist', //指定需要提供给本地服务的内容的路径,默认加载index.html文件,可根据需要修改
port: 8080, // 端口设置,默认8080
hot: true // 开启热更新,浏览器自动刷新
}
})
webpack.prod.config.js修改为如下内容:
const merge = require('webpack-merge')
const baseConfig = require('./webpack.base.config')
module.exports = merge(baseConfig, {
// 方便追踪源代码错误
devtool: 'source-map'
})
然后,我们修改下package.json中的dev和build命令:
"scripts": {
"dev": "webpack-dev-server --config build/webpack.dev.config.js --open --mode development",
"build": "webpack --config build/webpack.prod.config.js --mode production"
},
最后,尝试运行下npm run dev 和 npm run build,看运行结果是否正常!
搭建cvue-cli v2.0
- 首先安装相关依赖包(每个具体的作用就不介绍了,可自行百度)
npm install --save vue
npm install --save-dev vue-loader vue-template-compiler vue-style-loader css-loader
- 修改webpack.base.config.js文件,添加相应loader的配置规则,以及在plugins中添加vue-loader官方提供的魔法插件
module: {
rules: [
{
test: /\.vue$/,
use: ['vue-loader']
},
// 它会应用到普通的 `.css` 文件以及 `.vue` 文件中的 `<style>` 块,因为魔法插件VueLoaderPlugin
{
test: /\.css$/,
use: ['vue-style-loader', 'css-loader']
}
]
}
const VueLoaderPlugin = require('vue-loader/lib/plugin')
plugins: [
// 将定义过的其它规则复制并应用到 .vue 文件里相应语言的块
new VueLoaderPlugin()
]
-
添加App.vue文件
<template>
<div id="app"></div>
</template>
<script>
export default {
data() {
return {
message: 'hello cvue-cli'
}
}
}
</script>
<style>
#app {
color: red;
}
</style>
- 下面修改main.js文件,引入Vue的使用
import Vue from 'vue'
import App from './APP.vue'
new Vue({
el: '#app',
render: h => h(App)
})
注意:
new Vue({
el: '#app',
components: { App },
template: '<App/>'
})
如果在创建根实例时,采用上面的写法,浏览器会提示下面的错误:
引起该错误的原因和解决方法请查看下面的链接:
https://blog.csdn.net/wxl1555/article/details/83187647
- 修改index.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>cvue-cli</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
然后执行npm run dev,如果页面中出现了message对应的值,且字体为红色,说明vue单文件起作用了!
- 下面安装file-loader和url-loader
// 因为url-loader基于file-loader,所以都要安装。
// url-loader在file-loader上进行扩展,当文件小于多少KB时进行base64转换
npm install --save-dev file-loader url-loader
- 在webpack.base.config.js中添加文件loader的规则
// 图片文件处理
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000
}
}
},
// 音频文件
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000
}
}
},
// 字体文件
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000
}
}
}
-
在src目录下创建assets文件夹,用来存放我们的图片(这里使用vue官方logo),然后修改App.vue文件
<template>
<div id="app">
<img src="./assets/logo.png">
<h1>{{message}}</h1>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
message: 'hello cvue-cli'
}
}
}
</script>
<style>
#app {
text-align: center;
}
</style>
最后运行 npm run dev,如果浏览器中出现如下的样子,那么恭喜你,马上就可以完成cvue-cli v2.0的搭建了。怎么样?心里是不是有点小激动呢?别急,下面我们需要继续完善。
- 下面安装和使用vue-router
安装vue-router
npm install --save vue-router
添加相关文件,项目结构如下
hello-router.vue文件
<style>
.wrapper > h1 {
color: blue;
}
</style>
<template>
<div class="wrapper">
<h1>{{mesg}}</h1>
</div>
</template>
<script>
export default {
data() {
return {
mesg: "hello router"
}
}
}
</script>
index.js文件
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
const routes = [{
path: '/',
name: 'hello-router',
component: () => import('../components/hello-router.vue')
}]
const router = new Router({
routes
})
export default router
main.js文件
import Vue from 'vue'
import App from './APP.vue'
import router from './router/index'
new Vue({
el: '#app',
router,
render: h => h(App)
})
然后运行npm run dev,出现下图:
- 安装使用css预处理器-less
安装less和less-loader
npm install --save-dev less less-loader
在webpack.base.config.js中配置less-loader
{
test: /\.less$/,
use: ['vue-style-loader', 'css-loader', 'less-loader']
}
添加hello-router.less文件
.wrapper {
h2 {
color: green;
}
}
修改hello-router.vue
<style lang="less">
@import './hello-router.less';
.wrapper {
h1 {
color: purple;
}
}
</style>
<template>
<div class="wrapper">
<h1>{{mesg}}</h1>
<h2>{{mesg2}}</h2>
</div>
</template>
<script>
export default {
data() {
return {
mesg: 'hello router',
mesg2: 'i am mesg2!'
}
}
}
</script>
运行npm run dev,效果如下
下面我们在运行npm run build,然后在看下本地打包后的文件是否有问题。
至此,cvue-cli v2.0搭建完毕!
搭建cvue-cli v3.0
在cvue-cli v3.0中,我们需要将打包后的文件js和css该分离的分离,该压缩的压缩!
1.分离css样式
安装mini-css-extract-plugin插件
npm install --save-dev mini-css-extract-plugin
然后在webpack.base.config.js中引入插件,并进行配置
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
// 将vue-style-loader替换为 MiniCssExtractPlugin.loader
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
},
{
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
}
new MiniCssExtractPlugin({
// 配置分离样式文件名,还有publicPath属性可根据需要进行配置
filename: 'css/[name].css'
})
运行npm run build,可查看分离出的css文件
2.使用ejs将html模板化
安装ejs-loader
npm install --save-dev ejs-loader
修改webpack.base.config.js,支持ejs
// 添加loader规则
{
test: /\.ejs$/,
use: ['ejs-loader']
}
// 修改插件配置
new HtmlWebpackPlugins({
filename: 'index.html', // 输出的html文件名,默认index.html
template: './public/index.ejs', // html模板路径,注意这里也是./而不是../
chunks: ['main'] // 指定在html自动引入的js打包文件
})
- 下面设置下文件缓存
在输出chunk时,我们可以通过hash来设置文件名。webpack提供了三种hash方式,分别是hash,chunkhash,contenthash。
- hasn
hash是项目工程级的,整个工程构建的文件hash都是一样的,所以只要工程文件有一个修改了,那么所有打包文件的hash都会改变,这明显不利于文件缓存,比如第三方库的chunk。 - chunkhash
chunkhash和hash不一样,它根据不同的入口文件(Entry)进行依赖文件解析、构建对应的chunk,生成对应的hash值。我们在生产环境里把一些公共库和程序入口文件区分开,单独打包构建,接着我们采用chunkhash的方式生成hash值,那么只要我们不改动公共库的代码,就可以保证其hash值不会受影响。 - contenthash
contenthash表示由文件内容产生的hash值,内容不同产生的contenthash值也不一样。在项目中,通常做法是把项目中css都抽离出对应的css文件来加以引用。
下面修改webpack.base.config.js
// 配置编译文件输出路径
output: {
// 以原始文件名的输出文件名
filename: 'js/[name].[chunkhash].js',
path: path.resolve(__dirname, '../dist')
}
// 配置编译文件输出路径
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash].css'
})
修改HtmlWebpackPlugins插件的配置
// 设置html模板生成路径
new HtmlWebpackPlugins({
filename: 'index.html', // 输出的html文件名,默认index.html
template: './public/index.ejs', // html模板路径,注意这里也是./而不是../
chunks: ['main', 'vendor'], // 指定在html自动引入的js打包文件
})
然后大家可以分别试一下,加上chunkhash和contenthash有什么区别,是不是和上面介绍的那样。
最后运行npm run buil打包,打开index.html,看页面是否显示正常。
-
热更新(HMR)不能和[chunkhash]同时使用
按照上面的步骤,在运行打包文件时,页面在时可以正常显示的。但是如果运行了npm run dev,就会报如下错误:
这是因为热更新(HMR)不能和[chunkhash]同时使用。那么怎么办呢?好说,我们不是把配置分为了本地环境和生产环境吗?那么我们就在使用本地环境时不使用hash方式命名就可以啦!
修改webpack.dev.config.js 文件
const merge = require('webpack-merge')
const baseConfig = require('./webpack.base.config')
const path = require('path')
module.exports = merge(baseConfig, {
// 配置编译文件输出路径
output: {
// 以原始文件名的输出文件名
filename: 'js/[name].js',
path: path.resolve(__dirname, '../dist')
},
devServer: {
contentBase: './dist', //指定需要提供给本地服务的内容的路径,默认加载index.html文件,可根据需要修改
port: 8080, // 端口设置,默认8080
hot: true // 开启热更新,浏览器自动刷新
}
})
- 将项目的引入的图片等文件进行分离
修改webpack.base.config.js
// 图片文件处理
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: {
loader: 'url-loader',
options: {
limit: 0, // 这设为0,因为如果文件大小小于limit设置的值,会直接转为base64
outputPath: 'images'
}
}
}
运行 npm run build,在打包后的项目目录结构中会多出一个images文件夹。其他文件的分离方式也类似,如果需要可以自行配置。
结语
按照上面方式,就可以搭建出一个基本的仿vue-cli的脚手架。建议大家还是亲自去试一试,这样可以加深理解。
最后在附上本项目的git地址,大家可以下来看看:
cvue-cli的git地址
好啦,本篇文章内容到此结束,如果对上面的内容有什么不同的理解或是发现了错误,欢迎大家来交流指正。
感谢收看! \o(^o^)o