Skip to content

Commit abd7306

Browse files
author
Guillaume Chau
committed
refactor(ui): plugins connector is now multi-project
1 parent 090c52d commit abd7306

File tree

10 files changed

+169
-116
lines changed

10 files changed

+169
-116
lines changed

packages/@vue/cli-ui/apollo-server/api/PluginApi.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ const sharedData = require('../connectors/shared-data')
55
const views = require('../connectors/views')
66
const suggestions = require('../connectors/suggestions')
77
const folders = require('../connectors/folders')
8-
const cwd = require('../connectors/cwd')
98
const progress = require('../connectors/progress')
109
// Utils
1110
const ipc = require('../util/ipc')
@@ -22,12 +21,13 @@ const { validateSuggestion } = require('./suggestion')
2221
const { validateProgress } = require('./progress')
2322

2423
class PluginApi {
25-
constructor ({ plugins }, context) {
24+
constructor ({ plugins, file }, context) {
2625
// Context
2726
this.context = context
2827
this.pluginId = null
2928
this.project = null
3029
this.plugins = plugins
30+
this.cwd = file
3131
// Hooks
3232
this.hooks = {
3333
projectOpen: [],
@@ -362,8 +362,7 @@ class PluginApi {
362362
*/
363363
hasPlugin (id) {
364364
if (['vue-router', 'vuex'].includes(id)) {
365-
const folder = cwd.get()
366-
const pkg = folders.readPackage(folder, this.context, true)
365+
const pkg = folders.readPackage(this.cwd, this.context, true)
367366
return ((pkg.dependencies && pkg.dependencies[id]) || (pkg.devDependencies && pkg.devDependencies[id]))
368367
}
369368
return this.plugins.some(p => matchesPluginId(id, p.id))
@@ -402,15 +401,15 @@ class PluginApi {
402401
* Get current working directory.
403402
*/
404403
getCwd () {
405-
return cwd.get()
404+
return this.cwd()
406405
}
407406

408407
/**
409408
* Resolves a file relative to current working directory
410409
* @param {string} file Path to file relative to project
411410
*/
412411
resolve (file) {
413-
return path.resolve(cwd.get(), file)
412+
return path.resolve(this.cwd, file)
414413
}
415414

416415
/**

packages/@vue/cli-ui/apollo-server/connectors/configurations.js

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const fileTypes = ['js', 'json', 'yaml']
1818
let current = {}
1919

2020
function list (context) {
21-
return plugins.getApi().configurations
21+
return plugins.getApi(cwd.get()).configurations
2222
}
2323

2424
function findOne (id, context) {
@@ -183,13 +183,17 @@ async function getPromptTabs (id, context) {
183183
}
184184
await prompts.start()
185185

186-
plugins.callHook('configRead', [{
187-
config,
188-
data,
189-
onReadData,
190-
tabs,
191-
cwd: cwd.get()
192-
}], context)
186+
plugins.callHook({
187+
id: 'configRead',
188+
args: [{
189+
config,
190+
data,
191+
onReadData,
192+
tabs,
193+
cwd: cwd.get()
194+
}],
195+
file: cwd.get()
196+
}, context)
193197

194198
return tabs
195199
}
@@ -252,12 +256,16 @@ async function save (id, context) {
252256

253257
writeData({ config, data, changedFields }, context)
254258

255-
plugins.callHook('configWrite', [{
256-
config,
257-
data,
258-
changedFields,
259-
cwd: cwd.get()
260-
}], context)
259+
plugins.callHook({
260+
id: 'configWrite',
261+
args: [{
262+
config,
263+
data,
264+
changedFields,
265+
cwd: cwd.get()
266+
}],
267+
file: cwd.get()
268+
}, context)
261269

262270
current = {}
263271
}

packages/@vue/cli-ui/apollo-server/connectors/plugins.js

Lines changed: 91 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const path = require('path')
22
const fs = require('fs')
33
const LRU = require('lru-cache')
4+
const chalk = require('chalk')
45
// Subs
56
const channels = require('../channels')
67
// Connectors
@@ -47,14 +48,13 @@ const logoCache = new LRU({
4748
// Local
4849
let currentPluginId
4950
let eventsInstalled = false
50-
let plugins = []
51-
let pluginApi
5251
let installationStep
53-
let projectId
52+
let pluginsStore = new Map()
53+
let pluginApiInstances = new Map()
5454

55-
function list (file, context, resetApi = true) {
55+
async function list (file, context, resetApi = true) {
5656
const pkg = folders.readPackage(file, context)
57-
plugins = []
57+
let plugins = []
5858
plugins = plugins.concat(findPlugins(pkg.devDependencies || {}))
5959
plugins = plugins.concat(findPlugins(pkg.dependencies || {}))
6060

@@ -66,11 +66,14 @@ function list (file, context, resetApi = true) {
6666
plugins.unshift(service)
6767
}
6868

69-
if (resetApi) resetPluginApi(context)
69+
pluginsStore.set(file, plugins)
70+
71+
if (resetApi || !pluginApiInstances.get(file)) await resetPluginApi({ file }, context)
7072
return plugins
7173
}
7274

73-
function findOne (id, context) {
75+
function findOne ({ id, file }, context) {
76+
const plugins = getPlugins(file)
7477
return plugins.find(
7578
p => p.id === id
7679
)
@@ -90,54 +93,77 @@ function findPlugins (deps) {
9093
)
9194
}
9295

93-
function resetPluginApi (context) {
94-
// Clean up
95-
if (pluginApi) {
96-
pluginApi.views.forEach(r => views.remove(r.id, context))
97-
pluginApi.ipcHandlers.forEach(fn => ipc.off(fn))
98-
}
99-
sharedData.unWatchAll()
100-
101-
clientAddons.clear(context)
102-
suggestions.clear(context)
103-
104-
setTimeout(() => {
105-
const projects = require('./projects')
106-
const project = projects.getCurrent(context)
107-
108-
pluginApi = new PluginApi({
109-
plugins
110-
}, context)
96+
function getPlugins (file) {
97+
const plugins = pluginsStore.get(file)
98+
if (!plugins) return []
99+
return plugins
100+
}
111101

112-
if (projects.getType(project) !== 'vue') return
113-
114-
// Run Plugin API
115-
runPluginApi(path.resolve(__dirname, '../../'), context, 'ui-defaults')
116-
plugins.forEach(plugin => runPluginApi(plugin.id, context))
117-
runPluginApi(cwd.get(), context, 'vue-cli-ui')
118-
// Add client addons
119-
pluginApi.clientAddons.forEach(options => clientAddons.add(options, context))
120-
// Add views
121-
pluginApi.views.forEach(view => views.add(view, context))
122-
123-
if (!project) return
124-
projectId = project.id
125-
pluginApi.project = project
126-
if (projectId !== project.id) {
127-
callHook('projectOpen', [project, projects.getLast(context)], context)
128-
} else {
129-
callHook('pluginReload', [project], context)
102+
function resetPluginApi ({ file }, context) {
103+
return new Promise((resolve, reject) => {
104+
let pluginApi = pluginApiInstances.get(file)
105+
let projectId
130106

131-
// View open hook
132-
const currentView = views.getCurrent()
133-
if (currentView) views.open(currentView.id)
107+
// Clean up
108+
if (pluginApi) {
109+
projectId = pluginApi.project && pluginApi.project.id
110+
pluginApi.views.forEach(r => views.remove(r.id, context))
111+
pluginApi.ipcHandlers.forEach(fn => ipc.off(fn))
134112
}
135-
})
113+
sharedData.unWatchAll()
114+
115+
clientAddons.clear(context)
116+
suggestions.clear(context)
117+
118+
// Cyclic dependency with projects connector
119+
setTimeout(() => {
120+
const projects = require('./projects')
121+
const project = projects.getCurrent(context)
122+
const plugins = getPlugins(file)
123+
124+
pluginApi = new PluginApi({
125+
plugins,
126+
file
127+
}, context)
128+
pluginApiInstances.set(file, pluginApi)
129+
130+
if (projects.getType(project) !== 'vue') return
131+
132+
// Run Plugin API
133+
runPluginApi(path.resolve(__dirname, '../../'), pluginApi, context, 'ui-defaults')
134+
plugins.forEach(plugin => runPluginApi(plugin.id, pluginApi, context))
135+
runPluginApi(cwd.get(), pluginApi, context, 'vue-cli-ui')
136+
// Add client addons
137+
pluginApi.clientAddons.forEach(options => clientAddons.add(options, context))
138+
// Add views
139+
pluginApi.views.forEach(view => views.add(view, context))
140+
141+
if (!project) return
142+
pluginApi.project = project
143+
if (projectId !== project.id) {
144+
callHook({
145+
id: 'projectOpen',
146+
args: [project, projects.getLast(context)],
147+
file
148+
}, context)
149+
} else {
150+
callHook({
151+
id: 'pluginReload',
152+
args: [project],
153+
file
154+
}, context)
155+
156+
// View open hook
157+
const currentView = views.getCurrent()
158+
if (currentView) views.open(currentView.id)
159+
}
136160

137-
return true
161+
resolve(true)
162+
})
163+
})
138164
}
139165

140-
function runPluginApi (id, context, fileName = 'ui') {
166+
function runPluginApi (id, pluginApi, context, fileName = 'ui') {
141167
let module
142168
try {
143169
module = loadModule(`${id}/${fileName}`, cwd.get(), true)
@@ -149,7 +175,7 @@ function runPluginApi (id, context, fileName = 'ui') {
149175
if (module) {
150176
pluginApi.pluginId = id
151177
module(pluginApi)
152-
log('Plugin API loaded for', id)
178+
log('Plugin API loaded for', id, chalk.grey(pluginApi.cwd))
153179
pluginApi.pluginId = null
154180
}
155181

@@ -160,7 +186,14 @@ function runPluginApi (id, context, fileName = 'ui') {
160186
} catch (e) {}
161187
}
162188

163-
function callHook (id, args, context) {
189+
function getApi (folder) {
190+
const pluginApi = pluginApiInstances.get(folder)
191+
if (!pluginApi) throw new Error(`No plugin API available for ${folder}`)
192+
return pluginApi
193+
}
194+
195+
function callHook ({ id, args, file }, context) {
196+
const pluginApi = getApi(file)
164197
const fns = pluginApi.hooks[id]
165198
log(`Hook ${id}`, fns.length, 'handlers')
166199
fns.forEach(fn => fn(...args))
@@ -287,7 +320,7 @@ function runInvoke (id, context) {
287320
await invoke(id, prompts.getAnswers(), cwd.get())
288321
}
289322
// Run plugin api
290-
runPluginApi(id, context)
323+
runPluginApi(id, getApi(cwd.get()), context)
291324
installationStep = 'diff'
292325

293326
notify({
@@ -327,7 +360,7 @@ function update (id, context) {
327360
args: [id]
328361
})
329362
currentPluginId = id
330-
const plugin = findOne(id, context)
363+
const plugin = findOne({ id, file: cwd.get() }, context)
331364
const { current, wanted } = await dependencies.getVersion(plugin, context)
332365

333366
await updatePackage(cwd.get(), getCommand(cwd.get()), null, id)
@@ -343,11 +376,11 @@ function update (id, context) {
343376
icon: 'done'
344377
})
345378

346-
resetPluginApi(context)
379+
await resetPluginApi({ file: cwd.get() }, context)
347380
dependencies.invalidatePackage(id, context)
348381

349382
currentPluginId = null
350-
return findOne(id)
383+
return findOne({ id, file: cwd.get() }, context)
351384
})
352385
}
353386

@@ -387,17 +420,15 @@ async function updateAll (context) {
387420
icon: 'done'
388421
})
389422

390-
resetPluginApi(context)
423+
await resetPluginApi({ file: cwd.get() }, context)
391424

392425
return updatedPlugins
393426
})
394427
}
395428

396-
function getApi () {
397-
return pluginApi
398-
}
429+
async function callAction ({ id, params, file = cwd.get() }, context) {
430+
const pluginApi = getApi(file)
399431

400-
async function callAction ({ id, params }, context) {
401432
context.pubsub.publish(channels.PLUGIN_ACTION_CALLED, {
402433
pluginActionCalled: { id, params }
403434
})

0 commit comments

Comments
 (0)