25 Vue源代碼的打包
1.介紹
npm install vue@next --save
先安裝vue3
在webpack的入口文件main.js里面寫入以下代碼
import {createApp} from "vue"
const app = createApp({
template:"<h2>{{title}}</h2>",
data(){
return {
title:"i am vue"
}
}
});
app.mount("#app");
運行npm run build, 沒有報錯
然后打開dist中的index.html,發(fā)現(xiàn)并沒有顯示 i am vue
打開控制臺,發(fā)現(xiàn)報錯
runtime-core.esm-bundler.js:38 [Vue warn]: Component provided template option but runtime compilation is not supported in this build of Vue. Configure your bundler to alias "vue" to "vue/dist/vue.esm-bundler.js".

2. vue版本(runtime-compiler and runtime-only)

如果選擇對template進行打包,就需要選擇第一種,因為compiler就是對template進行編譯的。但是vue默認(rèn)使用的是版本二:runtime-only, 不包含對template的編譯,所以編譯不會成功,界面渲染不出來。
render函數(shù)就是直接渲染出來虛擬節(jié)點v-dom
runtime-compiler
使用
new Vue({
el:"#app",
template: '<App/>',//template替換el里面的內(nèi)容
components:{App}
})
當(dāng)我們把template傳給Vue實例的時候,它會被保存在Vue實例下面的options,
template被解析(parse)成抽象語法樹,ast(abstract syntax tree),
然后第三步,complier,編譯成render函數(shù)
通過render函數(shù)把template翻譯成virtual dom,虛擬dom
轉(zhuǎn)換成真實的dom
template(html)->ast->render ->vdom ->真實dom
runtime-only(1.性能更高 2.下面的vue代碼量更少)
new Vue({
el:'#app',
render:h => h(App)
})
render ->vdom ->真實dom
new Vue({
el:'#app',
render: function (createElement){
//1. 普通用法:傳入標(biāo)簽createElement('標(biāo)簽',{標(biāo)簽的屬性},[''])
/* return createElement('h2',
{class:'box'},
['Hello! world!', createElement('button', {class:'mybtn'}, ['按鈕'])]) */
//2.傳入組件對象:
//return createElement(cpn)
return createElement(App)
//創(chuàng)建出來的標(biāo)簽,替換掉之前的<div id="app"><div>
//那么.vue文件中的template是由誰編譯的呢?
//是由vue-template-compier來解析的,將.vue里面的template解析成render函數(shù)的,在main.js里面引用的不是整個.vue文件
//引用的是被解析后的App對象,對象里面沒有包含任何關(guān)于tenplate信息,所有的template已經(jīng)轉(zhuǎn)成render函數(shù)了
}
})
簡單總結(jié)
如果在之后的開發(fā)中,你依然使用template,就需要選擇Runtime-Compiler
如果你之后的開發(fā)中,使用的是.vue文件夾開發(fā),那么可以選擇Runtime-only
3.vue打包后不同版本解析

D:\FrontEnd\07_codershy_Vue3s\webpack_study\code\06_webpack_vue\node_modules\vue\dist文件夾 里面有很多版本的vue。
vue.global.js就是我們cnd引入時候的文件。
如果你不需要編譯template,就可以只使用runtime的版本,vue.runtime.global.js
vue.runtime.global.prod.js 是要不要使用生產(chǎn)版本,生成版本是做過壓縮的。
-
vue.global.js包含編譯器和運行時的完整版,構(gòu)建過程中支持動態(tài)模板編譯 -
vue.runtime.global.js僅預(yù)編譯了構(gòu)建過程中的運行時和必要的模板
第二個是正常src引用的話,就是第一個方式,上面的方式,但是表明了src = .. type="module"的時候使用現(xiàn)在這個。
第三個是在wenpack等構(gòu)建工具中使用。分兩個,一個有complier,一個沒有。默認(rèn)使用的是只有runtime的版本 vue.runtime.esm-bundler.js, 不包含對template的解析,所以沒有顯示出來。
import {createApp} from 'vue/dist/vue.esm-bundler'
//這樣npm run build之后,就會渲染出來
//把main.js總的import換成'vue/dist/vue.esm-bundler' 而不是默認(rèn)的vue.runtime.esm-bundler.js
vue.runtime.esm-bundler.js(默認(rèn))僅運行時,且要求所有模板必須預(yù)編譯。這是構(gòu)建工具的默認(rèn)入口(通過package.js的module字段),因為當(dāng)使用構(gòu)建工具模板時一般都是預(yù)編譯的(例如:*.vue文件)
vue.esm.bundler.js:包含運行時編譯器。當(dāng)你使用了構(gòu)建工具但仍然想編譯運行時模板(例如,in-DOM模板或通過javascript字符的內(nèi)聯(lián)模板)。你需要在構(gòu)建工具中配置vue別名到這個文件。
vue.cjs(.prod).js:
- 服務(wù)端使用Nodejs通過require()渲染。
- 如果使用webpack指定
target: 'node'且正確的使用vue進行描述,發(fā)布時此文件將會載入。
Vue3x基礎(chǔ) - 安裝 - 簡書 (jianshu.com)
4.全局標(biāo)識的配置

5.VSCode對SFC文件的支持

6 編寫App.vue代碼

//main.js
import { sum } from "./js/math";
const { priceFormat } = require("./js/format");
import "./js/element.js"
import {createApp} from 'vue/dist/vue.esm-bundler'
import App from './vue/App.vue'
console.log(sum(20, 30));
console.log(priceFormat());
/* const app = createApp({
template: `<h2>我是vue渲染出來的</h2>`,
data(){
return {
title: "hello world"
}
}
}); */
const app = createApp(App)
app.mount("#app");
template在public的index.html里面,js在main.js里面,這樣的話比較麻煩,如果有樣式的話,就更麻煩了,三個部分在三個不同的文件里,為了解決這個問題,我們就有了.vue文件,把這三個部分放到一個文件里面。
在src里面創(chuàng)建一個vue文件夾,里面創(chuàng)建一個App.vue文件
App.vue
<template>
<h2>我是Vue渲染出來的</h2>
<h2>{{title}}</h2>
</template>
<script>
export default {
data() {
return {
title: "Hello world",
message:"hahahha"
}
},
methods: {
}
}
</script>
<style>
h2{
color: red;
}
</style>
main.js文件修改為以下
import {createApp} from "vue/dist/vue.esm-bundler"
import App from "./vue/App.vue"
const app = createApp(App )
/*雖然只導(dǎo)出了{
data() {
return {
title: "Hello world",
message:"hahahha"
}
},
methods: {
}
}
這個對象,但是其實會用一個loader對這個vue文件進行編譯,它會自動把template里面的東西放到導(dǎo)出的這個對象里面
*/
app.mount("#app");
然后運行npm run build 報錯了,原因是無法解析.vue文件
7. App.vue的打包過程
默認(rèn)情況下vue-loader是對vue2的源代碼進行解析的,所以我們要使用vue-loader@next
npm i vue-loader@next -d

然后修改配置文件
{
test:/\.vue$/,
loader:"vue-loader"
}
然后還是會報錯,因為vue-loader是依賴@vue/compiler-sfc這個包的,其實對單文件解析的時候是@vue/complier-sfc這個包對他進行解析的。vue2是@vue/vue-template-compiler.
npm i @vue/compiler-sfc -d
8. vue/complier-sfc

如上,對@vue/compiler-sfc 進行配置后,就可以npm run build進行打包。打開index文件。就可以看到我是Vue渲染出來的和Hello world。
9. GlobalFeatureFlags的配置
雖然正確的顯示出來了,但是console里面會有一下的報錯
runtime-core.esm-bundler.js:3705
Feature flags __VUE_OPTIONS_API__, __VUE_PROD_DEVTOOLS__ are not explicitly defined. You are running the esm-bundler build of Vue, which expects these compile-time feature flags to be globally injected via the bundler config in order to get better tree-shaking in the production bundle.
For more details, see https://github.com/vuejs/vue-next/tree/master/packages/vue#bundler-build-feature-flags
Starting with 3.0.0-rc.3, esm-bundler builds now exposes global feature flags that can be overwritten at compile time: 從3.0.0版本開始, esm-bundler要求我們設(shè)置一個global feature 的flag。這里面有兩個參數(shù)
-
__VUE_OPTIONS_API__(enable/disable Options API support, default:true)對vue2做適配,默認(rèn)是true,就是意味著源代碼里面是有一部分代碼是對vue-options-api做解析的,
如果代碼里面寫的都是setup()也就是vue3的代碼,我就不需要這部分代碼,你就可以設(shè)置為false,tree-shaking在打包的時候,發(fā)現(xiàn)是false的話,就會把這一部分代碼從源代碼里面刪除掉,體積就會小一些
-
__VUE_PROD_DEVTOOLS__(enable/disable devtools support in production, default:false)生產(chǎn)環(huán)節(jié)下要不要支持devtool,devtool一般是開發(fā)階段使用,生產(chǎn)階段一般不用它生效,所以設(shè)置成false
new DefinePlugin({
BASE_URL : "'./'",
__VUE_OPTIONS_API__: true,
__VUE_PROD_DEVTOOLS__:false
}),
警告全部消除了
因為已經(jīng)使用了vue-loader和vue/complier-sfc對template等等進行處理
然后這時候可以直接使用
import {createApp} from "vue"