Skip to content

Commit 9a07eeb

Browse files
committed
feat: complete --target wc & multi-wc + tests
1 parent 4f095f0 commit 9a07eeb

19 files changed

+327
-58
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<template>
2+
<h1>{{ msg }}</h1>
3+
</template>
4+
5+
<script>
6+
export default {
7+
data: () => ({ msg: 'hi' })
8+
}
9+
</script>
10+
11+
<style>
12+
h1 { color: red }
13+
</style>

packages/@vue/cli-service-global/__tests__/globalService.spec.js

+1-13
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,7 @@ const binPath = require.resolve('@vue/cli/bin/vue')
1414
const sleep = n => new Promise(resolve => setTimeout(resolve, n))
1515
const write = (file, content) => fs.writeFileSync(path.join(cwd, file), content)
1616

17-
const entryVue = `
18-
<template>
19-
<h1>{{ msg }}</h1>
20-
</template>
21-
<script>
22-
export default {
23-
data: () => ({ msg: 'hi' })
24-
}
25-
</script>
26-
<style>
27-
h1 { color: red }
28-
</style>
29-
`.trim()
17+
const entryVue = fs.readFileSync(path.resolve(__dirname, 'entry.vue'), 'utf-8')
3018

3119
const entryJs = `
3220
import Vue from 'vue'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
jest.setTimeout(20000)
2+
3+
const fs = require('fs')
4+
const path = require('path')
5+
const portfinder = require('portfinder')
6+
const { createServer } = require('http-server')
7+
const mkdirp = require('mkdirp')
8+
const execa = require('execa')
9+
const launchPuppeteer = require('@vue/cli-test-utils/launchPuppeteer')
10+
11+
const cwd = path.resolve(__dirname, 'temp')
12+
const binPath = require.resolve('@vue/cli/bin/vue')
13+
const write = (file, content) => fs.writeFileSync(path.join(cwd, file), content)
14+
15+
const entryVue = fs.readFileSync(path.resolve(__dirname, 'entry.vue'), 'utf-8')
16+
17+
beforeAll(() => {
18+
mkdirp.sync(cwd)
19+
write('testLib.vue', entryVue)
20+
})
21+
22+
let server, browser, page
23+
test('global build --target lib', async () => {
24+
const { stdout } = await execa(binPath, ['build', 'testLib.vue', '--target', 'lib'], { cwd })
25+
26+
expect(stdout).toMatch('Build complete.')
27+
28+
const distDir = path.join(cwd, 'dist')
29+
const hasFile = file => fs.existsSync(path.join(distDir, file))
30+
expect(hasFile('demo.html')).toBe(true)
31+
expect(hasFile('testLib.common.js')).toBe(true)
32+
expect(hasFile('testLib.umd.js')).toBe(true)
33+
expect(hasFile('testLib.umd.min.js')).toBe(true)
34+
expect(hasFile('testLib.css')).toBe(true)
35+
36+
const port = await portfinder.getPortPromise()
37+
server = createServer({ root: distDir })
38+
39+
await new Promise((resolve, reject) => {
40+
server.listen(port, err => {
41+
if (err) return reject(err)
42+
resolve()
43+
})
44+
})
45+
46+
const launched = await launchPuppeteer(`http://localhost:${port}/demo.html`)
47+
browser = launched.browser
48+
page = launched.page
49+
50+
const h1Text = await page.evaluate(() => {
51+
return document.querySelector('h1').textContent
52+
})
53+
54+
expect(h1Text).toMatch('hi')
55+
})
56+
57+
afterAll(async () => {
58+
await browser.close()
59+
server.close()
60+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
jest.setTimeout(20000)
2+
3+
const fs = require('fs')
4+
const path = require('path')
5+
const portfinder = require('portfinder')
6+
const { createServer } = require('http-server')
7+
const mkdirp = require('mkdirp')
8+
const execa = require('execa')
9+
const launchPuppeteer = require('@vue/cli-test-utils/launchPuppeteer')
10+
11+
const cwd = path.resolve(__dirname, 'temp')
12+
const binPath = require.resolve('@vue/cli/bin/vue')
13+
const write = (file, content) => fs.writeFileSync(path.join(cwd, file), content)
14+
15+
const entryVue = fs.readFileSync(path.resolve(__dirname, 'entry.vue'), 'utf-8')
16+
17+
beforeAll(() => {
18+
mkdirp.sync(cwd)
19+
write('my-wc.vue', entryVue)
20+
})
21+
22+
let server, browser, page
23+
test('global build --target wc', async () => {
24+
const { stdout } = await execa(binPath, ['build', 'my-wc.vue', '--target', 'wc'], { cwd })
25+
26+
expect(stdout).toMatch('Build complete.')
27+
28+
const distDir = path.join(cwd, 'dist')
29+
const hasFile = file => fs.existsSync(path.join(distDir, file))
30+
expect(hasFile('demo.html')).toBe(true)
31+
expect(hasFile('my-wc.js')).toBe(true)
32+
expect(hasFile('my-wc.min.js')).toBe(true)
33+
34+
const port = await portfinder.getPortPromise()
35+
server = createServer({ root: distDir })
36+
37+
await new Promise((resolve, reject) => {
38+
server.listen(port, err => {
39+
if (err) return reject(err)
40+
resolve()
41+
})
42+
})
43+
44+
const launched = await launchPuppeteer(`http://localhost:${port}/demo.html`)
45+
browser = launched.browser
46+
page = launched.page
47+
48+
const h1Text = await page.evaluate(() => {
49+
return document.querySelector('my-wc')._shadowRoot.querySelector('h1').textContent
50+
})
51+
52+
expect(h1Text).toMatch('hi')
53+
})
54+
55+
afterAll(async () => {
56+
await browser.close()
57+
server.close()
58+
})

packages/@vue/cli-service-global/__tests__/globalServiceBuildWebComponent.spec.js

Whitespace-only changes.

packages/@vue/cli-service-global/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const { toPlugin, findExisting } = require('./lib/util')
66

77
const babelPlugin = toPlugin('@vue/cli-plugin-babel')
88
const eslintPlugin = toPlugin('@vue/cli-plugin-eslint')
9-
const createConfigPlugin = require('./lib/createConfigPlugin')
9+
const globalConfigPlugin = require('./lib/globalConfigPlugin')
1010

1111
function resolveEntry (entry) {
1212
const context = process.cwd()
@@ -44,7 +44,7 @@ function createService (context, entry, asLib) {
4444
plugins: [
4545
babelPlugin,
4646
eslintPlugin,
47-
createConfigPlugin(context, entry, asLib)
47+
globalConfigPlugin(context, entry, asLib)
4848
]
4949
})
5050
}

packages/@vue/cli-service-global/lib/createConfigPlugin.js renamed to packages/@vue/cli-service-global/lib/globalConfigPlugin.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ module.exports = function createConfigPlugin (context, entry, asLib) {
7171
.clear()
7272
.end()
7373
.exclude
74-
.add(/node_modules|@vue\/cli-service/)
74+
.add(/node_modules/)
75+
.add(/@vue\/cli-service/)
7576
.end()
7677
.uses
7778
.delete('cache-loader')

packages/@vue/cli-service/__tests__/buildLib.spec.js

+13-18
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,16 @@ const launchPuppeteer = require('@vue/cli-test-utils/launchPuppeteer')
99

1010
let server, browser, page
1111
test('build as lib', async () => {
12-
const project = await create('e2e-build-lib', defaultPreset)
12+
const project = await create('build-lib', defaultPreset)
1313

14-
const { stdout } = await project.run('vue-cli-service build --traget lib --name testLib')
14+
const { stdout } = await project.run('vue-cli-service build --target lib --name testLib src/components/HelloWorld.vue')
1515
expect(stdout).toMatch('Build complete.')
1616

17-
expect(project.has('dist/index.html')).toBe(true)
18-
expect(project.has('dist/favicon.ico')).toBe(true)
19-
expect(project.has('dist/js')).toBe(true)
20-
expect(project.has('dist/css')).toBe(true)
21-
22-
const index = await project.read('dist/index.html')
23-
// should preload app.js & vendor.js
24-
expect(index).toMatch(/<link rel=preload [^>]+app[^>]+\.js>/)
25-
expect(index).toMatch(/<link rel=preload [^>]+vendor[^>]+\.js>/)
26-
27-
const vendorFile = index.match(/<link rel=preload [^>]+(vendor[^>]+\.js)>/)[1]
28-
const vendor = await project.read(`dist/js/${vendorFile}`)
29-
expect(vendor).toMatch(`router-link`)
30-
expect(vendor).toMatch(`vuex`)
17+
expect(project.has('dist/demo.html')).toBe(true)
18+
expect(project.has('dist/testLib.common.js')).toBe(true)
19+
expect(project.has('dist/testLib.umd.js')).toBe(true)
20+
expect(project.has('dist/testLib.umd.min.js')).toBe(true)
21+
expect(project.has('dist/testLib.css')).toBe(true)
3122

3223
const port = await portfinder.getPortPromise()
3324
server = createServer({ root: path.join(project.dir, 'dist') })
@@ -39,15 +30,19 @@ test('build as lib', async () => {
3930
})
4031
})
4132

42-
const launched = await launchPuppeteer(`http://localhost:${port}/`)
33+
const launched = await launchPuppeteer(`http://localhost:${port}/demo.html`)
4334
browser = launched.browser
4435
page = launched.page
4536

4637
const h1Text = await page.evaluate(() => {
4738
return document.querySelector('h1').textContent
4839
})
40+
expect(h1Text).toMatch('') // no props given
4941

50-
expect(h1Text).toMatch('Welcome to Your Vue.js App')
42+
const h2Text = await page.evaluate(() => {
43+
return document.querySelector('h2').textContent
44+
})
45+
expect(h2Text).toMatch('Essential Links')
5146
})
5247

5348
afterAll(async () => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
jest.setTimeout(30000)
2+
3+
const path = require('path')
4+
const portfinder = require('portfinder')
5+
const { createServer } = require('http-server')
6+
const { defaultPreset } = require('@vue/cli/lib/options')
7+
const create = require('@vue/cli-test-utils/createTestProject')
8+
const launchPuppeteer = require('@vue/cli-test-utils/launchPuppeteer')
9+
10+
let server, browser, page
11+
test('build as single wc', async () => {
12+
const project = await create('build-multi-wc', defaultPreset)
13+
14+
const { stdout } = await project.run(`vue-cli-service build --target multi-wc **/*.vue`)
15+
expect(stdout).toMatch('Build complete.')
16+
17+
expect(project.has('dist/demo.html')).toBe(true)
18+
expect(project.has('dist/build-multi-wc.js')).toBe(true)
19+
expect(project.has('dist/build-multi-wc.min.js')).toBe(true)
20+
21+
const port = await portfinder.getPortPromise()
22+
server = createServer({ root: path.join(project.dir, 'dist') })
23+
24+
await new Promise((resolve, reject) => {
25+
server.listen(port, err => {
26+
if (err) return reject(err)
27+
resolve()
28+
})
29+
})
30+
31+
const launched = await launchPuppeteer(`http://localhost:${port}/demo.html`)
32+
browser = launched.browser
33+
page = launched.page
34+
35+
const styleCount = await page.evaluate(() => {
36+
return document.querySelector('build-multi-wc-app')._shadowRoot.querySelectorAll('style').length
37+
})
38+
expect(styleCount).toBe(2) // should contain styles from both app and child
39+
40+
const h1Text = await page.evaluate(() => {
41+
return document.querySelector('build-multi-wc-app')._shadowRoot.querySelector('h1').textContent
42+
})
43+
expect(h1Text).toMatch('Welcome to Your Vue.js App')
44+
45+
const childStyleCount = await page.evaluate(() => {
46+
return document.querySelector('build-multi-wc-hello-world')._shadowRoot.querySelectorAll('style').length
47+
})
48+
expect(childStyleCount).toBe(1)
49+
50+
const h2Text = await page.evaluate(() => {
51+
return document.querySelector('build-multi-wc-hello-world')._shadowRoot.querySelector('h2').textContent
52+
})
53+
expect(h2Text).toMatch('Essential Links')
54+
})
55+
56+
afterAll(async () => {
57+
await browser.close()
58+
server.close()
59+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
jest.setTimeout(30000)
2+
3+
const path = require('path')
4+
const portfinder = require('portfinder')
5+
const { createServer } = require('http-server')
6+
const { defaultPreset } = require('@vue/cli/lib/options')
7+
const create = require('@vue/cli-test-utils/createTestProject')
8+
const launchPuppeteer = require('@vue/cli-test-utils/launchPuppeteer')
9+
10+
let server, browser, page
11+
test('build as single wc', async () => {
12+
const project = await create('build-wc', defaultPreset)
13+
14+
const { stdout } = await project.run('vue-cli-service build --target wc src/components/HelloWorld.vue')
15+
expect(stdout).toMatch('Build complete.')
16+
17+
expect(project.has('dist/demo.html')).toBe(true)
18+
expect(project.has('dist/build-wc.js')).toBe(true)
19+
expect(project.has('dist/build-wc.min.js')).toBe(true)
20+
21+
const port = await portfinder.getPortPromise()
22+
server = createServer({ root: path.join(project.dir, 'dist') })
23+
24+
await new Promise((resolve, reject) => {
25+
server.listen(port, err => {
26+
if (err) return reject(err)
27+
resolve()
28+
})
29+
})
30+
31+
const launched = await launchPuppeteer(`http://localhost:${port}/demo.html`)
32+
browser = launched.browser
33+
page = launched.page
34+
35+
const styleCount = await page.evaluate(() => {
36+
return document.querySelector('build-wc')._shadowRoot.querySelectorAll('style').length
37+
})
38+
expect(styleCount).toBe(1)
39+
40+
await page.evaluate(() => {
41+
document.querySelector('build-wc').msg = 'hello'
42+
})
43+
const h1Text = await page.evaluate(() => {
44+
return document.querySelector('build-wc')._shadowRoot.querySelector('h1').textContent
45+
})
46+
expect(h1Text).toBe('hello')
47+
})
48+
49+
afterAll(async () => {
50+
await browser.close()
51+
server.close()
52+
})

packages/@vue/cli-service/__tests__/buildWebComponent.spec.js

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<title><%- htmlWebpackPlugin.options.libName %> demo</title>
2+
<script src="https://unpkg.com/vue"></script>
3+
<script src="./<%- htmlWebpackPlugin.options.libName %>.js"></script>
4+
<% for (const comp of htmlWebpackPlugin.options.components) { %>
5+
<<%= comp %>></<%= comp %>>
6+
<% } %>

packages/@vue/cli-service/lib/commands/build/generateMultiWcEntry.js

+17-6
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,30 @@ const hyphenate = str => {
1111
return str.replace(hyphenateRE, '-$1').toLowerCase()
1212
}
1313

14-
module.exports = function generateMultiWebComponentEntry (prefix, files) {
14+
exports.filesToComponentNames = (prefix, files) => {
15+
return files.map(file => {
16+
const basename = path.basename(file).replace(/\.(jsx?|vue)$/, '')
17+
const camelName = camelize(basename)
18+
const kebabName = `${prefix}-${hyphenate(basename)}`
19+
return {
20+
file,
21+
basename,
22+
camelName,
23+
kebabName
24+
}
25+
})
26+
}
27+
28+
exports.generateMultiWebComponentEntry = (prefix, files) => {
1529
const filePath = path.resolve(__dirname, 'entry-multi-wc.js')
1630
const content = `
1731
import Vue from 'vue'
1832
import wrap from '@vue/web-component-wrapper'
1933
20-
${files.map(file => {
21-
const basename = path.basename(file).replace(/\.(jsx?|vue)$/, '')
22-
const camelName = camelize(basename)
23-
const kebabName = hyphenate(basename)
34+
${exports.filesToComponentNames(prefix, files).map(({ file, camelName, kebabName }) => {
2435
return (
2536
`import ${camelName} from '~root/${file}'\n` +
26-
`window.customElements.define('${prefix}-${kebabName}', wrap(Vue, ${camelName}))\n`
37+
`window.customElements.define('${kebabName}', wrap(Vue, ${camelName}))\n`
2738
)
2839
}).join('\n')}`.trim()
2940
fs.writeFileSync(filePath, content)

0 commit comments

Comments
 (0)