Skip to content

Commit 0f59c03

Browse files
committed
feat: vue build --target multi-wc [pattern]
1 parent 1c4943b commit 0f59c03

11 files changed

+91
-36
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
entry-multi-wc.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import Vue from 'vue'
2+
import wrap from '@vue/web-component-wrapper'
3+
import Component from '~entry'
4+
5+
window.customElements.define(
6+
process.env.CUSTOM_ELEMENT_NAME,
7+
wrap(Vue, Component)
8+
)

packages/@vue/cli-service/lib/commands/build/entry-web-component.js

-12
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const fs = require('fs')
2+
const path = require('path')
3+
4+
const camelizeRE = /-(\w)/g
5+
const camelize = str => {
6+
return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
7+
}
8+
9+
const hyphenateRE = /\B([A-Z])/g
10+
const hyphenate = str => {
11+
return str.replace(hyphenateRE, '-$1').toLowerCase()
12+
}
13+
14+
module.exports = function generateMultiWebComponentEntry (prefix, files) {
15+
const filePath = path.resolve(__dirname, 'entry-multi-wc.js')
16+
const content = `
17+
import Vue from 'vue'
18+
import wrap from '@vue/web-component-wrapper'
19+
20+
${files.map(file => {
21+
const basename = path.basename(file).replace(/\.(jsx?|vue)$/, '')
22+
const camelName = camelize(basename)
23+
const kebabName = hyphenate(basename)
24+
return (
25+
`import ${camelName} from '~root/${file}'\n` +
26+
`window.customElements.define('${prefix}-${kebabName}', wrap(Vue, ${camelName}))\n`
27+
)
28+
}).join('\n')}`.trim()
29+
fs.writeFileSync(filePath, content)
30+
return filePath
31+
}

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

+10-5
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,22 @@ const defaults = {
77
module.exports = (api, options) => {
88
api.registerCommand('build', {
99
description: 'build for production',
10-
usage: 'vue-cli-service build [options]',
10+
usage: 'vue-cli-service build [options] [entry|pattern]',
1111
options: {
1212
'--mode': `specify env mode (default: ${defaults.mode})`,
1313
'--dest': `specify output directory (default: ${options.outputDir})`,
14-
'--target': `app | lib | web-component (default: ${defaults.target})`,
15-
'--entry': `entry for lib or web-component (default: ${defaults.entry})`,
16-
'--name': `name for lib or web-component (default: "name" in package.json or entry filename)`
14+
'--target': `app | lib | wc | multi-wc (default: ${defaults.target})`,
15+
'--name': `name for lib or (multi-)web-component mode (default: "name" in package.json or entry filename)`
1716
}
1817
}, args => {
18+
args.entry = args._[0]
1919
for (const key in defaults) {
2020
if (args[key] == null) args[key] = defaults[key]
2121
}
2222
if (args.dest == null) {
2323
args.dest = options.outputDir
2424
}
25+
2526
api.setMode(args.mode)
2627

2728
const chalk = require('chalk')
@@ -51,7 +52,11 @@ module.exports = (api, options) => {
5152
let webpackConfig
5253
if (args.target === 'lib') {
5354
webpackConfig = require('./resolveLibConfig')(api, args, options)
54-
} else if (args.target === 'web-component' || args.target === 'wc') {
55+
} else if (
56+
args.target === 'web-component' ||
57+
args.target === 'wc' ||
58+
args.target === 'multi-wc'
59+
) {
5560
webpackConfig = require('./resolveWebComponentConfig')(api, args, options)
5661
} else {
5762
webpackConfig = api.resolveWebpackConfig()

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

+34-13
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,31 @@
11
const path = require('path')
22

3-
module.exports = (api, { entry, name, dest }) => {
4-
const libName = name || api.service.pkg.name || entry.replace(/\.(js|vue)$/, '')
5-
if (libName.indexOf('-') < 0) {
6-
const { log, error } = require('@vue/cli-shared-utils')
3+
module.exports = (api, { target, entry, name, dest, prefix }) => {
4+
const { log, error } = require('@vue/cli-shared-utils')
5+
const abort = msg => {
76
log()
8-
error(`--name must contain a hyphen when building as web-component. (got "${libName}")`)
7+
error(msg)
98
process.exit(1)
109
}
1110

11+
const libName = name || api.service.pkg.name || entry.replace(/\.(js|vue)$/, '')
12+
if (libName.indexOf('-') < 0 && target !== 'multi-wc') {
13+
abort(`--name must contain a hyphen with --target web-component. (got "${libName}")`)
14+
}
15+
16+
let dynamicEntry
17+
if (target === 'multi-wc') {
18+
if (!entry) {
19+
abort(`a glob pattern is required with --target multi-web-component.`)
20+
}
21+
// generate dynamic entry based on glob files
22+
const files = require('globby').sync([entry], { cwd: api.resolve('.') })
23+
if (!files.length) {
24+
abort(`glob pattern "${entry}" did not match any files.`)
25+
}
26+
dynamicEntry = require('./generateMultiWcEntry')(libName, files)
27+
}
28+
1229
// setting this disables app-only configs
1330
process.env.VUE_CLI_TARGET = 'web-component'
1431
// inline all static asset files since there is no publicPath handling
@@ -20,18 +37,22 @@ module.exports = (api, { entry, name, dest }) => {
2037
const config = api.resolveChainableWebpackConfig()
2138

2239
config.entryPoints.clear()
40+
2341
// set proxy entry for *.vue files
24-
if (/\.vue$/.test(entry)) {
42+
if (target === 'multi-wc') {
2543
config
26-
.entry(`${libName}${minify ? `.min` : ``}`)
27-
.add(require.resolve('./entry-web-component.js'))
44+
.entry(`${libName}${minify ? `.min` : ``}`)
45+
.add(dynamicEntry)
2846
config.resolve
29-
.alias
30-
.set('~entry', api.resolve(entry))
47+
.alias
48+
.set('~root', api.resolve('.'))
3149
} else {
3250
config
33-
.entry(`${libName}${minify ? `.min` : ``}`)
34-
.add(api.resolve(entry))
51+
.entry(`${libName}${minify ? `.min` : ``}`)
52+
.add(require.resolve('./entry-wc.js'))
53+
config.resolve
54+
.alias
55+
.set('~entry', api.resolve(entry))
3556
}
3657

3758
// only minify min entry
@@ -70,7 +91,7 @@ module.exports = (api, { entry, name, dest }) => {
7091
config
7192
.plugin('demo-html')
7293
.use(require('html-webpack-plugin'), [{
73-
template: path.resolve(__dirname, './demo-web-component.html'),
94+
template: path.resolve(__dirname, './demo-wc.html'),
7495
inject: false,
7596
filename: 'demo.html',
7697
libName

packages/@vue/cli-service/lib/webpack/resolveLoaderError.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const TYPE = 'cant-resolve-loader'
33
const errorRE = /Can't resolve '(.*loader)'/
44

55
exports.transformer = error => {
6-
if (error.webpackError) {
6+
if (error.webpackError && error.webpackError.message) {
77
const match = error.webpackError.message.match(errorRE)
88
if (match) {
99
return Object.assign({}, error, {

packages/@vue/cli-service/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"file-loader": "^1.1.6",
3939
"friendly-errors-webpack-plugin": "^1.6.1",
4040
"get-value": "^2.0.6",
41+
"globby": "^7.1.1",
4142
"html-webpack-plugin": "^2.30.1",
4243
"javascript-stringify": "^1.6.0",
4344
"launch-editor-middleware": "^2.2.0",
@@ -55,7 +56,7 @@
5556
"thread-loader": "^1.1.2",
5657
"uglifyjs-webpack-plugin": "^1.1.6",
5758
"url-loader": "^0.6.2",
58-
"vue-loader": "^14.0.3",
59+
"vue-loader": "^14.1.0",
5960
"vue-template-compiler": "^2.5.13",
6061
"webpack": "^3.10.0",
6162
"webpack-chain": "^4.5.0",

packages/@vue/cli/bin/vue.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ program
6464

6565
program
6666
.command('build [entry]')
67-
.option('-t, --target <target>', 'Build target (app | lib | web-component, default: app)')
67+
.option('-t, --target <target>', 'Build target (app | lib | wc, default: app)')
6868
.option('-n, --name <name>', 'name for lib or web-component (default: entry filename)')
6969
.option('-d, --dest <dir>', 'output directory (default: dist)')
7070
.description('build a .js or .vue file in production mode with zero config')

yarn.lock

+3-3
Original file line numberDiff line numberDiff line change
@@ -10077,9 +10077,9 @@ vue-jest@^2.0.0:
1007710077
tsconfig "^7.0.0"
1007810078
vue-template-es2015-compiler "^1.5.3"
1007910079

10080-
vue-loader@^14.0.3:
10081-
version "14.0.3"
10082-
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-14.0.3.tgz#26df42fb2a40e21e9799eb1adc15fff763b99bd2"
10080+
vue-loader@^14.1.0:
10081+
version "14.1.0"
10082+
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-14.1.0.tgz#ae31d62a11421061fca8bac30cbc15875df886d3"
1008310083
dependencies:
1008410084
consolidate "^0.14.0"
1008510085
hash-sum "^1.0.2"

0 commit comments

Comments
 (0)