Skip to content

Commit

Permalink
feat: allow choosing vue version on creation (and in presets) (#5637)
Browse files Browse the repository at this point in the history
  • Loading branch information
sodatea committed Jul 24, 2020
1 parent 7c2a36b commit b1772ca
Show file tree
Hide file tree
Showing 57 changed files with 3,431 additions and 3,969 deletions.
1 change: 1 addition & 0 deletions .eslintignore
@@ -1,5 +1,6 @@
node_modules
template
template-vue3
packages/test
temp
entry-wc.js
Expand Down
1 change: 0 additions & 1 deletion package.json
Expand Up @@ -91,7 +91,6 @@
},
"resolutions": {
"puppeteer": "1.11.0",
"vue": "^2.6.11",
"vue-template-compiler": "^2.6.11",
"vue-server-renderer": "^2.6.11"
}
Expand Down
2 changes: 1 addition & 1 deletion packages/@vue/babel-preset-app/README.md
Expand Up @@ -88,7 +88,7 @@ Use this option when you have 3rd party dependencies that are not processed by B

- Default: `true`.

Set to `false` to disable JSX support. Or you can toggle [@vue/babel-preset-jsx](https://github.com/vuejs/jsx/tree/dev/packages/babel-preset-jsx) features here.
Set to `false` to disable JSX support. Or you can toggle [@vue/babel-preset-jsx](https://github.com/vuejs/jsx/tree/dev/packages/babel-preset-jsx) (or [@ant-design-vue/babel-plugin-jsx](https://github.com/vueComponent/jsx) for Vue 3 projects) features here.

### loose

Expand Down
17 changes: 16 additions & 1 deletion packages/@vue/babel-preset-app/index.js
Expand Up @@ -112,7 +112,22 @@ module.exports = (context, options = {}) => {

// JSX
if (options.jsx !== false) {
presets.push([require('@vue/babel-preset-jsx'), typeof options.jsx === 'object' ? options.jsx : {}])
let jsxOptions = {}
if (typeof options.jsx === 'object') {
jsxOptions = options.jsx
}

let vueVersion = 2
try {
const Vue = require('vue')
vueVersion = semver.major(Vue.version)
} catch (e) {}

if (vueVersion === 2) {
presets.push([require('@vue/babel-preset-jsx'), jsxOptions])
} else if (vueVersion === 3) {
plugins.push([require('@ant-design-vue/babel-plugin-jsx'), jsxOptions])
}
}

const runtimePath = path.dirname(require.resolve('@babel/runtime/package.json'))
Expand Down
7 changes: 6 additions & 1 deletion packages/@vue/babel-preset-app/package.json
Expand Up @@ -22,6 +22,7 @@
},
"homepage": "https://github.com/vuejs/vue-cli/tree/dev/packages/@vue/babel-preset-app#readme",
"dependencies": {
"@ant-design-vue/babel-plugin-jsx": "^1.0.0-0",
"@babel/core": "^7.9.6",
"@babel/helper-compilation-targets": "^7.9.6",
"@babel/helper-module-imports": "^7.8.3",
Expand All @@ -40,11 +41,15 @@
},
"peerDependencies": {
"@babel/core": "*",
"core-js": "^3"
"core-js": "^3",
"vue": "^2 || ^3.0.0-0"
},
"peerDependenciesMeta": {
"core-js": {
"optional": true
},
"vue": {
"optional": true
}
}
}
Expand Up @@ -2,9 +2,6 @@ const create = require('@vue/cli-test-utils/createUpgradableProject')
const { logs } = require('@vue/cli-shared-utils')

jest.setTimeout(300000)
beforeEach(() => {
process.env.VUE_CLI_TEST_DO_INSTALL_PLUGIN = true
})

test('upgrade: plugin-babel v3.5', async () => {
const project = await create('plugin-babel-legacy', {
Expand Down
Expand Up @@ -63,6 +63,11 @@ beforeAll(async () => {
)
})

afterAll(async () => {
// avoid the non-existent made-up deps interfere with other tests
await project.rm('package.json')
})

test('dep from node_modules should not been transpiled', async () => {
await project.run('vue-cli-service build')
expect(await readVendorFile()).toMatch('() => "__TEST__"')
Expand Down
@@ -1,10 +1,6 @@
jest.setTimeout(300000)
jest.mock('inquirer')

beforeEach(() => {
process.env.VUE_CLI_TEST_DO_INSTALL_PLUGIN = true
})

const create = require('@vue/cli-test-utils/createUpgradableProject')
const { expectPrompts } = require('inquirer')

Expand Down
53 changes: 53 additions & 0 deletions packages/@vue/cli-plugin-eslint/__tests__/eslintVue3.spec.js
@@ -0,0 +1,53 @@
jest.setTimeout(300000)

const generateWithPlugin = require('@vue/cli-test-utils/generateWithPlugin')
const createOutside = require('@vue/cli-test-utils/createUpgradableProject')

test('Vue 3 base', async () => {
const { pkg } = await generateWithPlugin([
{
id: '@vue/cli-service',
apply: require('@vue/cli-service/generator'),
options: {
vueVersion: '3'
}
},
{
id: '@vue/cli-plugineslint',
apply: require('../generator'),
options: {}
}
])

expect(pkg.scripts.lint).toBeTruthy()
expect(pkg.eslintConfig.extends).toEqual([
'plugin:vue/vue3-essential', 'eslint:recommended'
])
})

test('Should allow fragments in Vue 3 projects', async () => {
const { write, run } = await createOutside('eslint-vue3-fragment', {
vueVersion: '3',
plugins: {
'@vue/cli-plugin-eslint': {}
}
})
await write('src/App.vue', `<template>
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>
`)

await run('vue-cli-service lint')
})
6 changes: 5 additions & 1 deletion packages/@vue/cli-plugin-eslint/eslintDeps.js
Expand Up @@ -28,9 +28,13 @@ const DEPS_MAP = {

exports.DEPS_MAP = DEPS_MAP

exports.getDeps = function (api, preset) {
exports.getDeps = function (api, preset, rootOptions = {}) {
const deps = Object.assign({}, DEPS_MAP.base, DEPS_MAP[preset])

if (rootOptions.vueVersion === '3') {
Object.assign(deps, { 'eslint-plugin-vue': '^7.0.0-0' })
}

if (api.hasPlugin('typescript')) {
Object.assign(deps, DEPS_MAP.typescript)
}
Expand Down
11 changes: 10 additions & 1 deletion packages/@vue/cli-plugin-eslint/eslintOptions.js
@@ -1,4 +1,4 @@
exports.config = (api, preset) => {
exports.config = (api, preset, rootOptions = {}) => {
const config = {
root: true,
env: { node: true },
Expand Down Expand Up @@ -40,6 +40,15 @@ exports.config = (api, preset) => {
}
}

if (rootOptions.vueVersion === '3') {
const updateConfig = cfg =>
cfg.replace(
/plugin:vue\/(essential|recommended|strongly-recommended)/gi,
'plugin:vue/vue3-$1'
)
config.extends = config.extends.map(updateConfig)
}

return config
}

Expand Down
6 changes: 3 additions & 3 deletions packages/@vue/cli-plugin-eslint/generator/index.js
@@ -1,9 +1,9 @@
const fs = require('fs')
const path = require('path')

module.exports = (api, { config, lintOn = [] }, _, invoking) => {
const eslintConfig = require('../eslintOptions').config(api, config)
const devDependencies = require('../eslintDeps').getDeps(api, config)
module.exports = (api, { config, lintOn = [] }, rootOptions, invoking) => {
const eslintConfig = require('../eslintOptions').config(api, config, rootOptions)
const devDependencies = require('../eslintDeps').getDeps(api, config, rootOptions)

const pkg = {
scripts: {
Expand Down
74 changes: 74 additions & 0 deletions packages/@vue/cli-plugin-router/__tests__/routerGenerator.spec.js
Expand Up @@ -62,3 +62,77 @@ test('use with Babel', async () => {

expect(pkg.dependencies).toHaveProperty('vue-router')
})

test('use with Vue 3', async () => {
const { files, pkg } = await generateWithPlugin([
{
id: '@vue/cli-service',
apply: require('@vue/cli-service/generator'),
options: {
vueVersion: '3'
}
},
{
id: '@vue/cli-plugin-router',
apply: require('../generator'),
options: {}
}
])

expect(files['src/router/index.js']).toBeTruthy()
expect(files['src/router/index.js']).toMatch('createRouter')
expect(files['src/router/index.js']).toMatch('history: createWebHashHistory()')

expect(files['src/main.js']).toMatch('.use(router)')

expect(pkg.dependencies).toHaveProperty('vue-router')
expect(pkg.dependencies['vue-router']).toMatch('^4')
})

test('Vue 3 + History Mode', async () => {
const { files } = await generateWithPlugin([
{
id: '@vue/cli-service',
apply: require('@vue/cli-service/generator'),
options: {
vueVersion: '3'
}
},
{
id: '@vue/cli-plugin-router',
apply: require('../generator'),
options: {
historyMode: true
}
}
])

expect(files['src/router/index.js']).toMatch(/import {.*createWebHistory/)
expect(files['src/router/index.js']).toMatch('history: createWebHistory(process.env.BASE_URL)')
})

test('Vue 3 + TypeScript', async () => {
const { files } = await generateWithPlugin([
{
id: '@vue/cli-service',
apply: require('@vue/cli-service/generator'),
options: {
vueVersion: '3'
}
},
{
id: '@vue/cli-plugin-router',
apply: require('../generator'),
options: {}
},
{
id: '@vue/cli-plugin-typescript',
apply: require('@vue/cli-plugin-typescript/generator'),
options: {}
}
])

expect(files['src/router/index.ts']).toBeTruthy()
expect(files['src/router/index.ts']).toMatch(/import {.*RouteRecordRaw/)
expect(files['src/router/index.ts']).toMatch('const routes: Array<RouteRecordRaw> =')
})
34 changes: 27 additions & 7 deletions packages/@vue/cli-plugin-router/generator/index.js
@@ -1,19 +1,39 @@
module.exports = (api, options = {}) => {
module.exports = (api, options = {}, rootOptions = {}) => {
const isVue3 = (rootOptions.vueVersion === '3')

api.injectImports(api.entryFile, `import router from './router'`)
api.injectRootOptions(api.entryFile, `router`)

api.extendPackage({
dependencies: {
'vue-router': '^3.2.0'
}
})
if (isVue3) {
api.transformScript(api.entryFile, require('./injectUseRouter'))
api.extendPackage({
dependencies: {
'vue-router': '^4.0.0-0'
}
})
} else {
api.injectRootOptions(api.entryFile, `router`)

api.extendPackage({
dependencies: {
'vue-router': '^3.2.0'
}
})
}

api.render('./template', {
historyMode: options.historyMode,
doesCompile: api.hasPlugin('babel') || api.hasPlugin('typescript'),
hasTypeScript: api.hasPlugin('typescript')
})

if (isVue3) {
api.render('./template-vue3', {
historyMode: options.historyMode,
doesCompile: api.hasPlugin('babel') || api.hasPlugin('typescript'),
hasTypeScript: api.hasPlugin('typescript')
})
}

if (api.invoking) {
if (api.hasPlugin('typescript')) {
/* eslint-disable-next-line node/no-extraneous-require */
Expand Down
29 changes: 29 additions & 0 deletions packages/@vue/cli-plugin-router/generator/injectUseRouter.js
@@ -0,0 +1,29 @@
module.exports = (file, api) => {
const j = api.jscodeshift
const root = j(file.source)

const appRoots = root.find(j.CallExpression, (node) => {
if (j.Identifier.check(node.callee) && node.callee.name === 'createApp') {
return true
}

if (
j.MemberExpression.check(node.callee) &&
j.Identifier.check(node.callee.object) &&
node.callee.object.name === 'Vue' &&
j.Identifier.check(node.callee.property) &&
node.callee.property.name === 'createApp'
) {
return true
}
})

appRoots.replaceWith(({ node: createAppCall }) => {
return j.callExpression(
j.memberExpression(createAppCall, j.identifier('use')),
[j.identifier('router')]
)
})

return root.toSource()
}

0 comments on commit b1772ca

Please sign in to comment.