Skip to content

Commit dbcd562

Browse files
committed
fix+refactor(auto-import): Port the auto-import feature from Quasar CLI (compatible with TS now) #33 #32 #19 #37
1 parent 851c448 commit dbcd562

7 files changed

+117
-84
lines changed

generator/index.js

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
const fs = require('fs'),
2-
extendPluginOptions = require('../lib/extendPluginOptions'),
3-
extendBabel = require('../lib/extendBabel')
2+
extendPluginOptions = require('../lib/extendPluginOptions')
43

54
const message = `
65
Documentation can be found at: https://quasar.dev
@@ -57,9 +56,7 @@ module.exports = (api, opts) => {
5756

5857
const deps = {
5958
dependencies,
60-
devDependencies: {
61-
'babel-plugin-transform-imports': '1.5.0'
62-
}
59+
devDependencies: {}
6360
}
6461

6562
if (opts.quasar.cssPreprocessor === 'styl') {
@@ -122,8 +119,6 @@ module.exports = (api, opts) => {
122119
}
123120

124121
api.onCreateComplete(() => {
125-
extendBabel(api)
126-
127122
let lines = `import Vue from 'vue'\n`
128123

129124
const

index.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,16 @@ module.exports = (api, options) => {
4747
.options(strategy)
4848
.before('cache-loader')
4949
}
50-
else if (![void 0, 'manual'].includes(strategy)) {
50+
else if (strategy !== void 0 && strategy !== 'manual') {
5151
console.error(`Incorrect setting for quasar > importStrategy (${strategy})`)
5252
console.error(`Use one of: 'kebab', 'pascal', 'combined', 'manual'.`)
5353
console.log()
5454
process.exit(1)
5555
}
56+
57+
chain.module.rule('transform-quasar-imports')
58+
.test(/\.(t|j)sx?$/)
59+
.use('transform-quasar-imports')
60+
.loader(path.join(__dirname, 'lib/loader.transform-quasar-imports.js'))
5661
})
5762
}

lib/extendBabel.js

-37
This file was deleted.

lib/get-devland-file.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module.exports = function getDevlandFile (name) {
2+
return require(
3+
require.resolve(name, {
4+
paths: [ __dirname ]
5+
})
6+
)
7+
}

lib/loader.auto-import.js

+44-39
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
function getDevlandFile (name) {
2-
return require(
3-
require.resolve(name, {
4-
paths: [ __dirname ]
5-
})
6-
)
7-
}
1+
const stringifyRequest = require('loader-utils/lib/stringifyRequest')
2+
const getDevlandFile = require('./get-devland-file.js')
83

94
const data = getDevlandFile('quasar/dist/babel-transforms/auto-import.json')
5+
const importTransform = getDevlandFile('quasar/dist/babel-transforms/imports.js')
6+
const runtimePath = require.resolve('./runtime.auto-import.js')
107

118
const compRegex = {
129
'?kebab': new RegExp(data.regex.kebabComponents || data.regex.components, 'g'),
@@ -21,68 +18,76 @@ const funcCompRegex = new RegExp(
2118

2219
const dirRegex = new RegExp(data.regex.directives, 'g')
2320

24-
function extract (content, form) {
25-
let comp = content.match(compRegex[form])
26-
const directives = content.match(dirRegex)
21+
function transform (itemArray) {
22+
return itemArray
23+
.map(name => `import ${name} from '${importTransform(name)}';`)
24+
.join(`\n`)
25+
}
26+
27+
function extract (content, ctx) {
28+
let comp = content.match(compRegex[ctx.query])
29+
let dir = content.match(dirRegex)
30+
31+
if (comp === null && dir === null) {
32+
return
33+
}
34+
35+
let importStatements = ''
36+
let installStatements = ''
2737

2838
if (comp !== null) {
2939
// avoid duplicates
3040
comp = Array.from(new Set(comp))
3141

3242
// map comp names only if not pascal-case already
33-
if (form !== '?pascal') {
43+
if (ctx.query !== '?pascal') {
3444
comp = comp.map(name => data.importName[name])
3545
}
3646

37-
if (form === '?combined') {
47+
if (ctx.query === '?combined') {
3848
// could have been transformed QIcon and q-icon too,
3949
// so avoid duplicates
4050
comp = Array.from(new Set(comp))
4151
}
4252

43-
comp = comp.join(',')
44-
}
45-
else {
46-
comp = ''
53+
importStatements += transform(comp)
54+
installStatements += `qInstall(component, 'components', {${comp.join(',')}});`
4755
}
4856

49-
return {
50-
comp,
57+
if (dir !== null) {
58+
dir = Array.from(new Set(dir))
59+
.map(name => data.importName[name])
5160

52-
dir: directives !== null
53-
? Array.from(new Set(directives))
54-
.map(name => data.importName[name])
55-
.join(',')
56-
: ''
61+
importStatements += transform(dir)
62+
installStatements += `qInstall(component, 'directives', {${dir.join(',')}});`
5763
}
64+
65+
// stringifyRequest needed so it doesn't
66+
// messes up consistency of hashes between builds
67+
return `
68+
${importStatements}
69+
import qInstall from ${stringifyRequest(ctx, runtimePath)};
70+
${installStatements}
71+
`
5872
}
5973

60-
module.exports = function (content) {
74+
module.exports = function (content, map) {
75+
let newContent = content
76+
6177
if (!this.resourceQuery && funcCompRegex.test(content) === false) {
6278
const file = this.fs.readFileSync(this.resource, 'utf-8').toString()
63-
const { comp, dir } = extract(file, this.query)
79+
const code = extract(file, this)
6480

65-
const hasComp = comp !== ''
66-
const hasDir = dir !== ''
67-
68-
if (hasComp === true || hasDir === true) {
81+
if (code !== void 0) {
6982
const index = this.mode === 'development'
7083
? content.indexOf('/* hot reload */')
7184
: -1
7285

73-
const code = `\nimport {${comp}${hasComp === true && hasDir === true ? ',' : ''}${dir}} from 'quasar'\n` +
74-
(hasComp === true
75-
? `component.options.components = Object.assign(Object.create(component.options.components || null), component.options.components || {}, {${comp}})\n`
76-
: '') +
77-
(hasDir === true
78-
? `component.options.directives = Object.assign(Object.create(component.options.directives || null), component.options.directives || {}, {${dir}})\n`
79-
: '')
80-
81-
return index === -1
86+
newContent = index === -1
8287
? content + code
8388
: content.slice(0, index) + code + content.slice(index)
8489
}
8590
}
8691

87-
return content
92+
return this.callback(null, newContent, map)
8893
}
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const getDevlandFile = require('./get-devland-file.js')
2+
const importTransform = getDevlandFile('quasar/dist/babel-transforms/imports.js')
3+
4+
const regex = /import\s*\{([\w,\s]+)\}\s*from\s*['"]{1}quasar['"]{1}/g
5+
6+
module.exports = function (content, map) {
7+
const newContent = content.replace(
8+
regex,
9+
(_, match) => match.split(',')
10+
.map(identifier => {
11+
const data = identifier.split(' as ')
12+
13+
if (data[1] !== void 0) {
14+
return `import ${data[1].trim()} from '${importTransform(data[0].trim())}';`
15+
}
16+
17+
const name = data[0].trim()
18+
return `import ${name} from '${importTransform(name)}';`
19+
})
20+
.join('')
21+
)
22+
23+
return this.callback(null, newContent, map)
24+
}

lib/runtime.auto-import.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Quasar runtime for auto-importing
3+
* components or directives.
4+
*
5+
* Warning! This file does NOT get transpiled by Babel
6+
* but is included into the UI code.
7+
*
8+
* @param {component} Vue Component object
9+
* @param {type} One of 'components' or 'directives'
10+
* @param {items} Object containing components or directives
11+
*/
12+
module.exports = function qInstall (component, type, items) {
13+
var opt
14+
15+
if (typeof component.exports === 'function') {
16+
opt = component.exports.extendOptions
17+
opt[type] = component.exports.options[type]
18+
}
19+
else {
20+
opt = component.options
21+
}
22+
23+
if (opt[type] === void 0) {
24+
opt[type] = items
25+
}
26+
else {
27+
var target = opt[type]
28+
for (var i in items) {
29+
if (target[i] === void 0) {
30+
target[i] = items[i]
31+
}
32+
}
33+
}
34+
}

0 commit comments

Comments
 (0)