Skip to content

Commit

Permalink
feat(build): add --inline-vue flag to optionally disable externaliz…
Browse files Browse the repository at this point in the history
…ation of Vue (vuejs#4261)

Resolves vuejs#4055.
  • Loading branch information
romansp authored and haoqunjiang committed Aug 19, 2019
1 parent 497fd5a commit 86f4f5f
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 10 deletions.
12 changes: 12 additions & 0 deletions docs/guide/build-targets.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ App is the default build target. In this mode:

::: tip Note on Vue Dependency
In lib mode, Vue is *externalized*. This means the bundle will not bundle Vue even if your code imports Vue. If the lib is used via a bundler, it will attempt to load Vue as a dependency through the bundler; otherwise, it falls back to a global `Vue` variable.

To avoid this behavior provide `--inline-vue` flag to `build` command.

```
vue-cli-service build --target lib --inline-vue
```
:::

You can build a single entry as a library using
Expand Down Expand Up @@ -68,6 +74,12 @@ Web Component mode does not support IE11 and below. [More details](https://githu

::: tip Note on Vue Dependency
In web component mode, Vue is *externalized.* This means the bundle will not bundle Vue even if your code imports Vue. The bundle will assume `Vue` is available on the host page as a global variable.

To avoid this behavior provide `--inline-vue` flag to `build` command.

```
vue-cli-service build --target wc --inline-vue
```
:::

You can build a single entry as a web component using
Expand Down
1 change: 1 addition & 0 deletions docs/guide/cli-service.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ Options:
--modern build app targeting modern browsers with auto fallback
--target app | lib | wc | wc-async (default: app)
--formats list of output formats for library builds (default: commonjs,umd,umd-min)
--inline-vue include the Vue module in the final bundle of library or web component target
--name name for lib or web-component mode (default: "name" in package.json or entry filename)
--no-clean do not remove the dist directory before building the project
--report generate report.html to help analyze bundle content
Expand Down
12 changes: 12 additions & 0 deletions docs/ru/guide/build-targets.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@

::: tip Примечание о зависимости Vue
В режиме библиотеки Vue *экстернализируется*. Это означает, что сборка не будет содержать Vue, даже если ваш код его импортирует. Если библиотека используется через сборщик, он должен попытаться загрузить Vue в качестве зависимости через сборщик; в противном случае, он должен вернуться к глобальной переменной `Vue`.

Чтобы избежать экстернализиции Vue установите флаг `--inline-vue` для команды `build`.

```
vue-cli-service build --target lib --inline-vue
```
:::

Вы можете запустить сборку одной точки входа в качестве библиотеки с помощью:
Expand Down Expand Up @@ -72,6 +78,12 @@ module.exports = {

::: tip Примечание зависимости Vue
В режиме веб-компонентов Vue *экстернализируется.* Это означает, что сборка не будет содержать Vue, даже если ваш код его импортирует. Сборка будет подразумевать, что `Vue` доступен на странице в качестве глобальной переменной.

Чтобы избежать экстернализиции Vue установите флаг `--inline-vue` для команды `build`.

```
vue-cli-service build --target wc --inline-vue
```
:::

Вы можете запустить сборку одной точки входа в качестве веб-компонента с помощью:
Expand Down
1 change: 1 addition & 0 deletions docs/ru/guide/cli-service.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ npx vue-cli-service serve
--dest определить каталог сборки (по умолчанию: dist)
--modern собирать приложение для современных браузеров с авто-фоллбэком для старых
--target app | lib | wc | wc-async (по умолчанию: app)
--inline-vue включить Vue в содержимое сборки библиотеки или веб-компонента
--name имя библиотеки или режим веб-компонента (по умолчанию: "name" в package.json или имя файла точки входа)
--no-clean не удалять каталог dist перед сборкой проекта
--report сгенерировать report.html для анализа содержимого сборки
Expand Down
56 changes: 56 additions & 0 deletions packages/@vue/cli-service/__tests__/buildLib.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,59 @@ test('build as lib without --name and --filename options (default to package nam
expect(project.has('dist/test-lib.umd.js')).toBe(true)
expect(project.has('dist/test-lib.umd.min.js')).toBe(true)
})

test('build as lib with --inline-vue', async () => {
const project = await create('build-lib-inline-vue', defaultPreset)

await project.write('src/main-lib.js', `
import Vue from 'vue'
import App from "./components/App.vue"
document.addEventListener("DOMContentLoaded", function() {
new Vue({
render: h => h(App),
}).$mount('body');
});
`)

await project.write('src/components/App.vue', `
<template>
<div>{{ message }}<div>
</template>
<script>
export default {
data() {
return {
message: 'Hello from Lib'
}
},
}
</script>
`)

const { stdout } = await project.run('vue-cli-service build --target lib --inline-vue --name testLib src/main-lib.js')
expect(stdout).toMatch('Build complete.')

expect(project.has('dist/demo.html')).toBe(true)
expect(project.has('dist/testLib.common.js')).toBe(true)
expect(project.has('dist/testLib.umd.js')).toBe(true)
expect(project.has('dist/testLib.umd.min.js')).toBe(true)

const port = await portfinder.getPortPromise()
server = createServer({ root: path.join(project.dir, 'dist') })

await new Promise((resolve, reject) => {
server.listen(port, err => {
if (err) return reject(err)
resolve()
})
})

const launched = await launchPuppeteer(`http://localhost:${port}/demo.html`)
browser = launched.browser
page = launched.page
const divText = await page.evaluate(() => {
return document.querySelector('div').textContent
})
expect(divText).toMatch('Hello from Lib')
})
55 changes: 55 additions & 0 deletions packages/@vue/cli-service/__tests__/buildWc.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,61 @@ test('build as single wc', async () => {
expect(h1Text).toMatch('Welcome to Your Vue.js App')
})

test('build as wc with --inline-vue', async () => {
const project = await create('build-wc-inline-vue', defaultPreset)

await project.write('src/main-wc.js', `
import Vue from 'vue'
import App from "./components/App.vue"
document.addEventListener("DOMContentLoaded", function() {
new Vue({
render: h => h(App),
}).$mount('body');
});
`)

await project.write('src/components/App.vue', `
<template>
<div>{{ message }}<div>
</template>
<script>
export default {
data() {
return {
message: 'Hello from Wc'
}
},
}
</script>
`)

const { stdout } = await project.run('vue-cli-service build --target wc --inline-vue --name single-wc src/main-wc.js')
expect(stdout).toMatch('Build complete.')

expect(project.has('dist/demo.html')).toBe(true)
expect(project.has('dist/single-wc.js')).toBe(true)
expect(project.has('dist/single-wc.min.js')).toBe(true)

const port = await portfinder.getPortPromise()
server = createServer({ root: path.join(project.dir, 'dist') })

await new Promise((resolve, reject) => {
server.listen(port, err => {
if (err) return reject(err)
resolve()
})
})

const launched = await launchPuppeteer(`http://localhost:${port}/demo.html`)
browser = launched.browser
page = launched.page
const divText = await page.evaluate(() => {
return document.querySelector('div').textContent
})
expect(divText).toMatch('Hello from Wc')
})

afterEach(async () => {
if (browser) {
await browser.close()
Expand Down
1 change: 1 addition & 0 deletions packages/@vue/cli-service/bin/vue-cli-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const args = require('minimist')(rawArgv, {
'modern',
'report',
'report-json',
'inline-vue',
'watch',
// serve
'open',
Expand Down
1 change: 1 addition & 0 deletions packages/@vue/cli-service/lib/commands/build/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ module.exports = (api, options) => {
'--modern': `build app targeting modern browsers with auto fallback`,
'--no-unsafe-inline': `build app without introducing inline scripts`,
'--target': `app | lib | wc | wc-async (default: ${defaults.target})`,
'--inline-vue': 'include the Vue module in the final bundle of library or web component target',
'--formats': `list of output formats for library builds (default: ${defaults.formats})`,
'--name': `name for lib or web-component mode (default: "name" in package.json or entry filename)`,
'--filename': `file name for output, only usable for 'lib' target (default: value of --name)`,
Expand Down
14 changes: 8 additions & 6 deletions packages/@vue/cli-service/lib/commands/build/resolveLibConfig.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const fs = require('fs')
const path = require('path')

module.exports = (api, { entry, name, formats, filename }, options) => {
module.exports = (api, { entry, name, formats, filename, 'inline-vue': inlineVue }, options) => {
const { log, error } = require('@vue/cli-shared-utils')
const abort = msg => {
log()
Expand Down Expand Up @@ -97,11 +97,13 @@ module.exports = (api, { entry, name, formats, filename }, options) => {
rawConfig.externals = [
...(Array.isArray(rawConfig.externals) ? rawConfig.externals : [rawConfig.externals]),
{
vue: {
commonjs: 'vue',
commonjs2: 'vue',
root: 'Vue'
}
...(inlineVue || {
vue: {
commonjs: 'vue',
commonjs2: 'vue',
root: 'Vue'
}
})
}
].filter(Boolean)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const path = require('path')
const webpack = require('webpack')
const { resolveEntry, fileToComponentName } = require('./resolveWcEntry')

module.exports = (api, { target, entry, name }) => {
module.exports = (api, { target, entry, name, 'inline-vue': inlineVue }) => {
// Disable CSS extraction and turn on CSS shadow mode for vue-style-loader
process.env.VUE_CLI_CSS_SHADOW_MODE = true

Expand Down Expand Up @@ -99,9 +99,7 @@ module.exports = (api, { target, entry, name }) => {
// externalize Vue in case user imports it
rawConfig.externals = [
...(Array.isArray(rawConfig.externals) ? rawConfig.externals : [rawConfig.externals]),
{
vue: 'Vue'
}
{ ...(inlineVue || { vue: 'Vue' }) }
].filter(Boolean)

const entryName = `${libName}${minify ? `.min` : ``}`
Expand Down

0 comments on commit 86f4f5f

Please sign in to comment.