场景
vue3、webpack、vue-cli
npm run serve步骤
1.npm run serve
npm run xxx 就是执行package.json.scripts.xxx 对应值为vue-cli-service serve
接下来就找到vue-cli-service命令行文件,如下图:
找到对应的vue-cli-service.js文件如下图:
主要就是创建了一个Service类的实例,并且调用了实例的run方法,接下来看看这个Service实例是怎么写的
2.Service类
// ../lib/Service.js
module.exports = class Service {
constructor (context, { plugins, pkg, inlineOptions, useBuiltIn } = {}) {
process.VUE_CLI_SERVICE = this
this.initialized = false
this.context = context
this.inlineOptions = inlineOptions
this.webpackChainFns = []
this.webpackRawConfigFns = []
this.devServerConfigFns = []
this.commands = {}
// Folder containing the target package.json for plugins
this.pkgContext = context
// package.json containing the plugins
this.pkg = this.resolvePkg(pkg)
// If there are inline plugins, they will be used instead of those
// found in package.json.
// When useBuiltIn === false, built-in plugins are disabled. This is mostly
// for testing.
this.plugins = this.resolvePlugins(plugins, useBuiltIn)
// pluginsToSkip will be populated during run()
this.pluginsToSkip = new Set()
// resolve the default mode to use for each command
// this is provided by plugins as module.exports.defaultModes
// so we can get the information without actually applying the plugin.
this.modes = this.plugins.reduce((modes, { apply: { defaultModes } }) => {
return Object.assign(modes, defaultModes)
}, {})
}
async run (name, args = {}, rawArgv = []) {
// resolve mode
// prioritize inline --mode
// fallback to resolved default modes from plugins or development if --watch is defined
const mode = args.mode || (name === 'build' && args.watch ? 'development' : this.modes[name])
// --skip-plugins arg may have plugins that should be skipped during init()
this.setPluginsToSkip(args, rawArgv)
// load env variables, load user config, apply plugins
await this.init(mode)
args._ = args._ || []
let command = this.commands[name]
if (!command && name) {
error(`command "${name}" does not exist.`)
process.exit(1)
}
if (!command || args.help || args.h) {
command = this.commands.help
} else {
args._.shift() // remove command itself
rawArgv.shift()
}
console.log('fn',command);
const { fn } = command
return fn(args, rawArgv)
}
......一些内置的方法
}
遗留问题
根据上面代码可以得出:service.run(name,args,rawArgv)
(这里留个坑,不太明白args具体参数是什么),const service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd())
主要是不知道这个process全局变量怎么生成的,我查了下资料但是还是不明白,资料上面大致意思:
在 Vue CLI 项目中,
process
对象的模拟不是通过源代码直接构建的,而是通过 webpack 的配置来实现的。具体来说,process
对象的模拟是在 webpack 的配置文件中使用DefinePlugin
插件来完成的。
但是我是一开始run serve服务我是一步一步跟过来的,没有跳过一步,他怎么就给在Service类声明的文件里面就就有了process全局变量,我真不明白,后面再来填这个坑。
接下来看看run函数,首先根据传进来的是’build’还是’serve’设置mode变量,然后执行init(mode),最后返回一个函数,这个函数目前没看到有调用,暂时按下不表,那么接下来看看init函数
init (mode = process.env.VUE_CLI_MODE) {
if (this.initialized) {
return
}
this.initialized = true
this.mode = mode
// load mode .env
if (mode) {
this.loadEnv(mode)
}
// load base .env
this.loadEnv()
// load user config
const userOptions = this.loadUserOptions()
const loadedCallback = (loadedUserOptions) => {
this.projectOptions = defaultsDeep(loadedUserOptions, defaults())
debug('vue:project-config')(this.projectOptions)
// apply plugins.
this.plugins.forEach(({ id, apply }) => {
if (this.pluginsToSkip.has(id)) return
apply(new PluginAPI(id, this), this.projectOptions)
})
// apply webpack configs from project config file
if (this.projectOptions.chainWebpack) {
this.webpackChainFns.push(this.projectOptions.chainWebpack)
}
if (this.projectOptions.configureWebpack) {
this.webpackRawConfigFns.push(this.projectOptions.configureWebpack)
}
}
if (isPromise(userOptions)) {
return userOptions.then(loadedCallback)
} else {
return loadedCallback(userOptions)
}
}
init函数做了加载环境,用户的配置(vue.config.js) ,应用插件,整合项目的配置文件到webpack配置中一些事。
这就是为什么配置vue.config.js会起作用。
然后项目就启动了,至于怎么启动的这个fn函数后面再查,接下来看看重点,启动后项目资源结构。
浏览器的资源栏对应的是什么
使用 Webpack 启动 Vue 项目并在 Google Chrome 的开发者工具中查看源码时,顶层的目录(top directory),图片下三个子目录分别是:
1. localhost:8080
目录
localhost:8080
通常是本地开发服务器的地址。在开发过程中,Webpack Dev Server 或其他本地服务器会在这个地址上运行的应用。这个目录在开发者工具中显示,是为了能够方便地查看和调试运行在本地服务器上的代码。实际上,这个目录并不存在于文件系统中,而是开发者工具根据当前访问的URL动态生成的。
2. 项目名称目录(如 fof
)
项目名称目录(例如fof
)通常代表了项目的根目录。这个目录包含了项目的所有源代码文件,如Vue组件、JavaScript文件、CSS文件等。在开发者工具中,这个目录会以文件系统的形式展示,能够方便地查看和编辑项目中的文件。这个目录实际上存在于文件系统中,是开发者工具直接读取和展示项目文件的结果。
3. webpack-internal
目录
webpack-internal
目录包含了由Webpack内部生成的代码和资源。Webpack在打包过程中,会生成一些用于内部管理的代码和模块,例如模块映射、热更新(Hot Module Replacement)代码等。这些代码和模块对于Webpack的正常运行至关重要。在开发者工具中,这些代码会被归类到webpack-internal
目录下,以便能够查看和调试。这个目录并不存在于的文件系统中,而是由开发者工具根据Webpack打包生成的代码动态生成的。
下一个问题:
打印出来的导入的App。这些个属性我虽然知道是怎么出来的
import { render } from "./App.vue?vue&type=template&id=7ba5bd90"
import script from "./App.vue?vue&type=script&setup=true&lang=js"
export * from "./App.vue?vue&type=script&setup=true&lang=js"
import exportComponent from "../node_modules/vue-loader/dist/exportHelper.js"
const __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__file',"src/App.vue"]])
/* hot reload */
if (module.hot) {
__exports__.__hmrId = "7ba5bd90"
const api = __VUE_HMR_RUNTIME__
module.hot.accept()
if (!api.createRecord('7ba5bd90', __exports__)) {
api.reload('7ba5bd90', __exports__)
}
module.hot.accept("./App.vue?vue&type=template&id=7ba5bd90", () => {
api.rerender('7ba5bd90', render)
})
}
export default __exports__
这个文件是App.vue,__exports__就是上图返回的对象,那么这个对象是怎么出来的呢。
const __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__file',"src/App.vue"]])
script对应的是setup(),render对应的是render(),但是我们看到import过来的地址文件,"./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/App.vue?vue&type=script&setup=true&lang=js"
这些个文件却发现在babel中
而且每个.vue分别有type=script和type=template各一个,对应上面对象的setup()和render()函数,所以可以推断的是.vue文件的的template标签、script标签、style标签被分开了,现在目前知道的是template标签变成了render()渲染函数,script标签变成了setup()函数,那么style标签呢到哪儿去了?遗留问题 后面再查查。还有一个问题为什么会出现在babal-loader/lib里?
原文链接:https://juejin.cn/post/7340156047338782758 作者:坚持破冰