Skip to content

feat: support specifying directory for static files and template sources via a new publicDir option #3836

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 28 additions & 18 deletions docs/config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ Deprecated since Vue CLI 3.3, please use [`publicPath`](#publicPath) instead.
}
```

### publicDir

- Type: `string`
- Default: `'public'`

If present, the contents of this directory will be copied to `outputDir` to be served as public static files.

::: tip
Vue CLI tries to find template sources in this directory by default, it checks for `<publicDir>/index.html` or `<publicDir>/<pageName>.html` in multi-page mode.
Template sources are ignored automatically while static files are being copied to `outputDir`.
:::

### outputDir

- Type: `string`
Expand Down Expand Up @@ -111,24 +123,22 @@ Deprecated since Vue CLI 3.3, please use [`publicPath`](#publicPath) instead.
``` js
module.exports = {
pages: {
index: {
// entry for the page
entry: 'src/index/main.js',
// the source template
template: 'public/index.html',
// output as dist/index.html
home: {
// Entry file for this page
entry: 'src/home/main.js',
// The source template, defaults to "<publicDir>/<pageName>.html"
template: 'public/home.html',
// Name of the generated file on `outputDir`, defaults to "<pageName>.html"
filename: 'index.html',
// when using title option,
// template title tag needs to be <title><%= htmlWebpackPlugin.options.title %></title>
title: 'Index Page',
// chunks to include on this page, by default includes
// extracted common chunks and vendor chunks.
chunks: ['chunk-vendors', 'chunk-common', 'index']
// The page title. To use it in your template your title tag needs to be:
// <title><%= htmlWebpackPlugin.options.title %></title>
title: 'Home Page',
// Chunks to include on this page,
// by default includes its own chunk after the common and vendor chunks.
chunks: ['chunk-vendors', 'chunk-common', 'home']
},
// when using the entry-only string format,
// template is inferred to be `public/subpage.html`
// and falls back to `public/index.html` if not found.
// Output filename is inferred to be `subpage.html`.
// Alternatively you can specify only the page entry,
// all other options will use their defaults as described above.
subpage: 'src/subpage/main.js'
}
}
Expand Down Expand Up @@ -212,7 +222,7 @@ See [the plugin's README](https://github.com/vuejs/vue-cli/blob/dev/packages/%40

Configure the `crossorigin` attribute on `<link rel="stylesheet">` and `<script>` tags in generated HTML.

Note that this only affects tags injected by `html-webpack-plugin` - tags directly added in the source template (`public/index.html`) are not affected.
Note that this only affects tags injected by `html-webpack-plugin` - tags directly added in the source template (e.g. `public/index.html`) are not affected.

See also: [CORS settings attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes)

Expand All @@ -223,7 +233,7 @@ See [the plugin's README](https://github.com/vuejs/vue-cli/blob/dev/packages/%40

Set to `true` to enable [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) (SRI) on `<link rel="stylesheet">` and `<script>` tags in generated HTML. If you are hosting your built files on a CDN, it is a good idea to enable this for additional security.

Note that this only affects tags injected by `html-webpack-plugin` - tags directly added in the source template (`public/index.html`) are not affected.
Note that this only affects tags injected by `html-webpack-plugin` - tags directly added in the source template (e.g. `public/index.html`) are not affected.

Also, when SRI is enabled, preload resource hints are disabled due to a [bug in Chrome](https://bugs.chromium.org/p/chromium/issues/detail?id=677022) which causes the resources to be downloaded twice.

Expand Down
7 changes: 3 additions & 4 deletions packages/@vue/cli-service/lib/config/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module.exports = (api, options) => {

const isProd = process.env.NODE_ENV === 'production'
const isLegacyBundle = process.env.VUE_CLI_MODERN_MODE && !process.env.VUE_CLI_MODERN_BUILD
const publicDir = api.resolve(options.publicDir)
const outputDir = api.resolve(options.outputDir)

// code splitting
Expand Down Expand Up @@ -138,7 +139,7 @@ module.exports = (api, options) => {
const HTMLPlugin = require('html-webpack-plugin')
const PreloadPlugin = require('@vue/preload-webpack-plugin')
const multiPageConfig = options.pages
const htmlPath = api.resolve('public/index.html')
const htmlPath = api.resolve(`${publicDir}/index.html`)
const defaultHtmlPath = path.resolve(__dirname, 'index-default.html')
const publicCopyIgnore = ['.DS_Store']

Expand Down Expand Up @@ -180,7 +181,7 @@ module.exports = (api, options) => {
const pageConfig = normalizePageConfig(multiPageConfig[name])
const {
entry,
template = `public/${name}.html`,
template = `${publicDir}/${name}.html`,
filename = `${name}.html`,
chunks = ['chunk-vendors', 'chunk-common', name]
} = pageConfig
Expand Down Expand Up @@ -273,8 +274,6 @@ module.exports = (api, options) => {
}])
}

// copy static assets in public/
const publicDir = api.resolve('public')
if (!isLegacyBundle && fs.existsSync(publicDir)) {
webpackConfig
.plugin('copy')
Expand Down
9 changes: 7 additions & 2 deletions packages/@vue/cli-service/lib/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const { createSchema, validate } = require('@vue/cli-shared-utils')
const schema = createSchema(joi => joi.object({
baseUrl: joi.string().allow(''),
publicPath: joi.string().allow(''),
publicDir: joi.string(),
outputDir: joi.string(),
assetsDir: joi.string().allow(''),
indexPath: joi.string(),
Expand Down Expand Up @@ -74,11 +75,15 @@ function hasMultipleCores () {
}

exports.defaults = () => ({
// project deployment base
publicPath: '/',
// for compatibility concern. TODO: remove in v4.
baseUrl: '/',

// project deployment base
publicPath: '/',

// directory that can be used to place static files and template sources
publicDir: 'public',

// where to output built files
outputDir: 'dist',

Expand Down
1 change: 1 addition & 0 deletions packages/@vue/cli-service/types/ProjectOptions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ interface CSSOptions {

export interface ProjectOptions {
publicPath?: string;
publicDir?: string;
outputDir?: string;
assetsDir?: string;
indexPath?: string;
Expand Down