mirror of
https://github.com/vuejs/vue-cli.git
synced 2026-05-03 18:40:45 -05:00
feat: vue build --target multi-wc [pattern]
This commit is contained in:
@@ -0,0 +1 @@
|
||||
entry-multi-wc.js
|
||||
@@ -0,0 +1,8 @@
|
||||
import Vue from 'vue'
|
||||
import wrap from '@vue/web-component-wrapper'
|
||||
import Component from '~entry'
|
||||
|
||||
window.customElements.define(
|
||||
process.env.CUSTOM_ELEMENT_NAME,
|
||||
wrap(Vue, Component)
|
||||
)
|
||||
@@ -1,12 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import Component from '~entry'
|
||||
import wrap from '@vue/web-component-wrapper'
|
||||
|
||||
const name = process.env.CUSTOM_ELEMENT_NAME
|
||||
|
||||
// CSS injection function exposed by vue-loader & vue-style-loader
|
||||
const options = typeof Component === 'function' ? Component.options : Component
|
||||
const styleInjectors = window[options.__shadowInjectId]
|
||||
const onMounted = root => styleInjectors.forEach(inject => inject(root))
|
||||
|
||||
wrap(Vue, name, Component, onMounted)
|
||||
@@ -0,0 +1,31 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const camelizeRE = /-(\w)/g
|
||||
const camelize = str => {
|
||||
return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
|
||||
}
|
||||
|
||||
const hyphenateRE = /\B([A-Z])/g
|
||||
const hyphenate = str => {
|
||||
return str.replace(hyphenateRE, '-$1').toLowerCase()
|
||||
}
|
||||
|
||||
module.exports = function generateMultiWebComponentEntry (prefix, files) {
|
||||
const filePath = path.resolve(__dirname, 'entry-multi-wc.js')
|
||||
const content = `
|
||||
import Vue from 'vue'
|
||||
import wrap from '@vue/web-component-wrapper'
|
||||
|
||||
${files.map(file => {
|
||||
const basename = path.basename(file).replace(/\.(jsx?|vue)$/, '')
|
||||
const camelName = camelize(basename)
|
||||
const kebabName = hyphenate(basename)
|
||||
return (
|
||||
`import ${camelName} from '~root/${file}'\n` +
|
||||
`window.customElements.define('${prefix}-${kebabName}', wrap(Vue, ${camelName}))\n`
|
||||
)
|
||||
}).join('\n')}`.trim()
|
||||
fs.writeFileSync(filePath, content)
|
||||
return filePath
|
||||
}
|
||||
@@ -7,21 +7,22 @@ const defaults = {
|
||||
module.exports = (api, options) => {
|
||||
api.registerCommand('build', {
|
||||
description: 'build for production',
|
||||
usage: 'vue-cli-service build [options]',
|
||||
usage: 'vue-cli-service build [options] [entry|pattern]',
|
||||
options: {
|
||||
'--mode': `specify env mode (default: ${defaults.mode})`,
|
||||
'--dest': `specify output directory (default: ${options.outputDir})`,
|
||||
'--target': `app | lib | web-component (default: ${defaults.target})`,
|
||||
'--entry': `entry for lib or web-component (default: ${defaults.entry})`,
|
||||
'--name': `name for lib or web-component (default: "name" in package.json or entry filename)`
|
||||
'--target': `app | lib | wc | multi-wc (default: ${defaults.target})`,
|
||||
'--name': `name for lib or (multi-)web-component mode (default: "name" in package.json or entry filename)`
|
||||
}
|
||||
}, args => {
|
||||
args.entry = args._[0]
|
||||
for (const key in defaults) {
|
||||
if (args[key] == null) args[key] = defaults[key]
|
||||
}
|
||||
if (args.dest == null) {
|
||||
args.dest = options.outputDir
|
||||
}
|
||||
|
||||
api.setMode(args.mode)
|
||||
|
||||
const chalk = require('chalk')
|
||||
@@ -51,7 +52,11 @@ module.exports = (api, options) => {
|
||||
let webpackConfig
|
||||
if (args.target === 'lib') {
|
||||
webpackConfig = require('./resolveLibConfig')(api, args, options)
|
||||
} else if (args.target === 'web-component' || args.target === 'wc') {
|
||||
} else if (
|
||||
args.target === 'web-component' ||
|
||||
args.target === 'wc' ||
|
||||
args.target === 'multi-wc'
|
||||
) {
|
||||
webpackConfig = require('./resolveWebComponentConfig')(api, args, options)
|
||||
} else {
|
||||
webpackConfig = api.resolveWebpackConfig()
|
||||
|
||||
@@ -1,14 +1,31 @@
|
||||
const path = require('path')
|
||||
|
||||
module.exports = (api, { entry, name, dest }) => {
|
||||
const libName = name || api.service.pkg.name || entry.replace(/\.(js|vue)$/, '')
|
||||
if (libName.indexOf('-') < 0) {
|
||||
const { log, error } = require('@vue/cli-shared-utils')
|
||||
module.exports = (api, { target, entry, name, dest, prefix }) => {
|
||||
const { log, error } = require('@vue/cli-shared-utils')
|
||||
const abort = msg => {
|
||||
log()
|
||||
error(`--name must contain a hyphen when building as web-component. (got "${libName}")`)
|
||||
error(msg)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const libName = name || api.service.pkg.name || entry.replace(/\.(js|vue)$/, '')
|
||||
if (libName.indexOf('-') < 0 && target !== 'multi-wc') {
|
||||
abort(`--name must contain a hyphen with --target web-component. (got "${libName}")`)
|
||||
}
|
||||
|
||||
let dynamicEntry
|
||||
if (target === 'multi-wc') {
|
||||
if (!entry) {
|
||||
abort(`a glob pattern is required with --target multi-web-component.`)
|
||||
}
|
||||
// generate dynamic entry based on glob files
|
||||
const files = require('globby').sync([entry], { cwd: api.resolve('.') })
|
||||
if (!files.length) {
|
||||
abort(`glob pattern "${entry}" did not match any files.`)
|
||||
}
|
||||
dynamicEntry = require('./generateMultiWcEntry')(libName, files)
|
||||
}
|
||||
|
||||
// setting this disables app-only configs
|
||||
process.env.VUE_CLI_TARGET = 'web-component'
|
||||
// inline all static asset files since there is no publicPath handling
|
||||
@@ -20,18 +37,22 @@ module.exports = (api, { entry, name, dest }) => {
|
||||
const config = api.resolveChainableWebpackConfig()
|
||||
|
||||
config.entryPoints.clear()
|
||||
|
||||
// set proxy entry for *.vue files
|
||||
if (/\.vue$/.test(entry)) {
|
||||
if (target === 'multi-wc') {
|
||||
config
|
||||
.entry(`${libName}${minify ? `.min` : ``}`)
|
||||
.add(require.resolve('./entry-web-component.js'))
|
||||
.entry(`${libName}${minify ? `.min` : ``}`)
|
||||
.add(dynamicEntry)
|
||||
config.resolve
|
||||
.alias
|
||||
.set('~entry', api.resolve(entry))
|
||||
.alias
|
||||
.set('~root', api.resolve('.'))
|
||||
} else {
|
||||
config
|
||||
.entry(`${libName}${minify ? `.min` : ``}`)
|
||||
.add(api.resolve(entry))
|
||||
.entry(`${libName}${minify ? `.min` : ``}`)
|
||||
.add(require.resolve('./entry-wc.js'))
|
||||
config.resolve
|
||||
.alias
|
||||
.set('~entry', api.resolve(entry))
|
||||
}
|
||||
|
||||
// only minify min entry
|
||||
@@ -70,7 +91,7 @@ module.exports = (api, { entry, name, dest }) => {
|
||||
config
|
||||
.plugin('demo-html')
|
||||
.use(require('html-webpack-plugin'), [{
|
||||
template: path.resolve(__dirname, './demo-web-component.html'),
|
||||
template: path.resolve(__dirname, './demo-wc.html'),
|
||||
inject: false,
|
||||
filename: 'demo.html',
|
||||
libName
|
||||
|
||||
@@ -3,7 +3,7 @@ const TYPE = 'cant-resolve-loader'
|
||||
const errorRE = /Can't resolve '(.*loader)'/
|
||||
|
||||
exports.transformer = error => {
|
||||
if (error.webpackError) {
|
||||
if (error.webpackError && error.webpackError.message) {
|
||||
const match = error.webpackError.message.match(errorRE)
|
||||
if (match) {
|
||||
return Object.assign({}, error, {
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"file-loader": "^1.1.6",
|
||||
"friendly-errors-webpack-plugin": "^1.6.1",
|
||||
"get-value": "^2.0.6",
|
||||
"globby": "^7.1.1",
|
||||
"html-webpack-plugin": "^2.30.1",
|
||||
"javascript-stringify": "^1.6.0",
|
||||
"launch-editor-middleware": "^2.2.0",
|
||||
@@ -55,7 +56,7 @@
|
||||
"thread-loader": "^1.1.2",
|
||||
"uglifyjs-webpack-plugin": "^1.1.6",
|
||||
"url-loader": "^0.6.2",
|
||||
"vue-loader": "^14.0.3",
|
||||
"vue-loader": "^14.1.0",
|
||||
"vue-template-compiler": "^2.5.13",
|
||||
"webpack": "^3.10.0",
|
||||
"webpack-chain": "^4.5.0",
|
||||
|
||||
@@ -64,7 +64,7 @@ program
|
||||
|
||||
program
|
||||
.command('build [entry]')
|
||||
.option('-t, --target <target>', 'Build target (app | lib | web-component, default: app)')
|
||||
.option('-t, --target <target>', 'Build target (app | lib | wc, default: app)')
|
||||
.option('-n, --name <name>', 'name for lib or web-component (default: entry filename)')
|
||||
.option('-d, --dest <dir>', 'output directory (default: dist)')
|
||||
.description('build a .js or .vue file in production mode with zero config')
|
||||
|
||||
@@ -10077,9 +10077,9 @@ vue-jest@^2.0.0:
|
||||
tsconfig "^7.0.0"
|
||||
vue-template-es2015-compiler "^1.5.3"
|
||||
|
||||
vue-loader@^14.0.3:
|
||||
version "14.0.3"
|
||||
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-14.0.3.tgz#26df42fb2a40e21e9799eb1adc15fff763b99bd2"
|
||||
vue-loader@^14.1.0:
|
||||
version "14.1.0"
|
||||
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-14.1.0.tgz#ae31d62a11421061fca8bac30cbc15875df886d3"
|
||||
dependencies:
|
||||
consolidate "^0.14.0"
|
||||
hash-sum "^1.0.2"
|
||||
|
||||
Reference in New Issue
Block a user