VUE单文件组件开发
前言
首先需要阐明的是本文单文件开发最终实现的结果:**在 HTML 中通过引入打包后的 js 文件,然后使用组件标签即可渲染。**例如:
<!DOCTYPE html>
<html lang="en">
<body>
<div id="page">
<xk-head :msg="msg">2213</xk-head>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"></script>
<script src="./dist/main.js"></script>
<script>
var app = new Vue({
el: '#page',
data: {
msg: 'Hello Vue!123'
}
})
</script>
</body>
</html>
为什么没有把 vue 打包到
main.js
中?考虑到一个页面可能会用到多个组件,而多个组件可能并不是使用的一个 js 生成,因此将 VUE 使用 CDN 方式引入。为了避免引入的繁琐,样式文件也没有进行拆分。
快速开始
此部分只包含核心部分,代码可能不可以直接使用。
既然想要把vue
单文件打包成 js 文件,那么核心就是webpack
和vue-loader
。
截至到目前(2021-07-04)为止,vue-loader 最新版本为 16+,但是 16 版本是针对 VUE3 的,而我所要使用的则是 VUE2 版本,因此并不能使用最新版本。因此需要安装的版本依赖如下:
{
"@babel/core": "^7.14.6",
"babel-loader": "8.2.2",
"babel-preset-env": "^1.7.0",
"vue-loader": "15.9.7",
"vue-style-loader": "^4.1.3",
"vue-template-compiler": "^2.6.14",
"webpack": "5.42.0",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.11.2"
}
接下来配置 webpack(只列出了核心配置)
// webpack.config.js
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
mode: 'development',
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
// 它会应用到普通的 `.js` 文件
// 以及 `.vue` 文件中的 `<script>` 块
{
test: /\.js$/,
loader: 'babel-loader'
},
// 它会应用到普通的 `.css` 文件
// 以及 `.vue` 文件中的 `<style>` 块
{
test: /\.css$/,
use: ['vue-style-loader', 'css-loader']
}
]
},
plugins: [
// 请确保引入这个插件来施展魔法
new VueLoaderPlugin()
]
}
vue-loader15 版本后需要引入一个
VueLoaderPlugin
的 plugin 才可以使用。并且在 15 版本后 vue 中对应的 js 和 css 会分别对应其后缀的文件进行解析。
不出意外此时即可编译出一个 js,将其引入到 HTML 中即可实现。
优化配置
以src
为开发目录进行配置
webpack 配置文件
入口文件
因为我们开发的是单文件组件,因此入口文件可能不止一个(不同类型或用途的组件),因此我们的入口最好是动态获取。
/** * @description: 获取入口 */ const fs = require('fs') const { parse, resolve } = require('path') /** * 传入路径获取入口文件配置 * @date 2021-05-18 * @param {String} path 入口js文件夹 * @returns {Object} 入口配置对象 */ const getEntry = (path) => { const files = fs.readdirSync(path) const entry = {} files.forEach((item) => { const { name, ext, base } = parse(resolve(__dirname, path, item)) // 如果ext存在,则认为是入口js文件 if (ext) { entry[name] = resolve(path, base) } }) return entry } module.exports = getEntry
向外暴露一个函数,参数传入一个路径,该函数会返回入口文件的对象。
loader
由于 loader 包含的类型比较多(sass、scss、stylus 等)因此我会讲他单独提取出来。
module.exports = [ require('./stylus'), require('./less.js'), require('./sass'), require('./scss'), require('./css'), require('./javascript'), require('./image'), require('./font'), require('./font'), require('./vue') ]
通过一个入口文件,向外暴露一个 loader 的列表。
// stylus示例 const stylus = { test: /\.styl(us)?$/, use: [ 'vue-style-loader', { loader: 'css-loader', options: { importLoaders: 1 } }, 'postcss-loader', 'stylus-loader' ] } module.exports = stylus
其他 loader 也是如此配置
plugins
plugins 由于只用到了两个,且不需要过多配置,因此个人认为无需提取。
其他
例如
mode
和devtool
则是根据环境变量和个人需求进行配置。
组件开发
入口文件
这里入口文件暂定为
/src/components
目录下的每一个 js 文件。// 导入头部组件 import head from '../components/head/head.vue' /** * 全局filter */ import filterInit from '../util/filter' filterInit(Vue) Vue.component(head.name, head) Vue.config.devtools = process.env.NODE_ENV === 'production' ? false : true window.Vue = Vue
问题
vue-loader
版本问题vue-loader
版本 16 只支持 vue3,因此如果使用 vue2 则需要使用 15.x 版本.组件库
例如
elementui
组件库import { Button } from 'element-ui' Vue.component(Button.name, Button)