mirror of
https://github.com/vitejs/vite.git
synced 2024-11-22 07:09:05 +00:00
parent
f4719e4441
commit
470ceb8276
@ -94,7 +94,7 @@ export default ({ command, mode }) => {
|
||||
- **Type:** `string`
|
||||
- **Default:** `process.cwd()`
|
||||
|
||||
Project root directory. Can be an absolute path, or a path relative from the location of the config file itself.
|
||||
Project root directory (where `index.html` is located). Can be an absolute path, or a path relative from the location of the config file itself.
|
||||
|
||||
See [Project Root](/guide/#project-root) for more details.
|
||||
|
||||
@ -111,6 +111,13 @@ export default ({ command, mode }) => {
|
||||
|
||||
See [Public Base Path](/guide/build#public-base-path) for more details.
|
||||
|
||||
### publicDir
|
||||
|
||||
- **Type:** `string`
|
||||
- **Default:** `"public"`
|
||||
|
||||
Directory to serve as plain static assets. Files in this directory are served at `/` during dev and copied to the root of `outDir` during build, and are always served or copied as-is without transform. The value can be either an absolute file system path or a path relative to project root.
|
||||
|
||||
### mode
|
||||
|
||||
- **Type:** `string`
|
||||
|
@ -182,6 +182,8 @@ If you have assets that are:
|
||||
|
||||
Then you can place the asset in a special `public` directory under your project root. Assets in this directory will be served at root path `/` during dev, and copied to the root of the dist directory as-is.
|
||||
|
||||
The directory defaults to `<root>/public`, but can be configured via the [`publicDir` option](/config/#publicdir).
|
||||
|
||||
Note that:
|
||||
|
||||
- You should always reference `public` assets using root absolute path - for example, `public/icon.png` should be referenced in source code as `/icon.png`.
|
||||
|
@ -48,7 +48,7 @@ One thing you may have noticed is that in a Vite project, `index.html` is front-
|
||||
|
||||
Vite treats `index.html` as source code and part of the module graph. It resolves `<script type="module" src="...">` that references your JavaScript source code. Even inline `<script type="module">` and CSS referenced via `<link href>` also enjoy Vite-specific features. In addition, URLs inside `index.html` are automatically rebased so there's no need for special `%PUBLIC_URL%` placeholders.
|
||||
|
||||
Similar to static http servers, Vite has the concept of a "root directory" from which your files are served from. Absolute URLs in your source code will be resolved using the project root as base, so you can write code as if you are working with a normal static file server (except way more powerful!). Vite is also capable of handling dependencies that resolve to out-of-root file system locations, which makes it usable even in a monorepo-based setup.
|
||||
Similar to static http servers, Vite has the concept of a "root directory" from which your files are served from. You will see it referenced as `<root>` throughout the rest of the docs. Absolute URLs in your source code will be resolved using the project root as base, so you can write code as if you are working with a normal static file server (except way more powerful!). Vite is also capable of handling dependencies that resolve to out-of-root file system locations, which makes it usable even in a monorepo-based setup.
|
||||
|
||||
Vite also supports [multi-page apps](./build#multi-page-app) with multiple `.html` entry points.
|
||||
|
||||
|
@ -6,18 +6,20 @@
|
||||
|
||||
<p class="base"></p>
|
||||
|
||||
<h2>Raw References from /public</h2>
|
||||
<h2>Raw References from publicDir</h2>
|
||||
<ul>
|
||||
<li class="raw-js"></li>
|
||||
<script src="/raw.js"></script>
|
||||
<li class="raw-css">Raw CSS from /public should load (this should be red)</li>
|
||||
<li class="raw-css">
|
||||
Raw CSS from publicDir should load (this should be red)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>Asset Imports from JS</h2>
|
||||
<ul>
|
||||
<li>Relative: <code class="asset-import-relative"></code></li>
|
||||
<li>Absolute: <code class="asset-import-absolute"></code></li>
|
||||
<li>From /public: <code class="public-import"></code></li>
|
||||
<li>From publicDir: <code class="public-import"></code></li>
|
||||
</ul>
|
||||
|
||||
<h2>CSS url references</h2>
|
||||
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
@ -3,6 +3,7 @@
|
||||
*/
|
||||
module.exports = {
|
||||
base: '/foo/',
|
||||
publicDir: 'static',
|
||||
build: {
|
||||
outDir: 'dist/foo'
|
||||
}
|
||||
|
@ -307,7 +307,6 @@ async function doBuild(
|
||||
}
|
||||
|
||||
const outDir = resolve(options.outDir)
|
||||
const publicDir = resolve('public')
|
||||
|
||||
// inject ssr arg to plugin load/transform hooks
|
||||
const plugins = (ssr
|
||||
@ -395,8 +394,8 @@ async function doBuild(
|
||||
)
|
||||
}
|
||||
}
|
||||
if (fs.existsSync(publicDir)) {
|
||||
copyDir(publicDir, outDir)
|
||||
if (fs.existsSync(config.publicDir)) {
|
||||
copyDir(config.publicDir, outDir)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,13 @@ export interface UserConfig {
|
||||
* @default '/'
|
||||
*/
|
||||
base?: string
|
||||
/**
|
||||
* Directory to serve as plain static assets. Files in this directory are
|
||||
* served and copied to build dist dir as-is without transform. The value
|
||||
* can be either an absolute file system path or a path relative to <root>.
|
||||
* @default 'public'
|
||||
*/
|
||||
publicDir?: string
|
||||
/**
|
||||
* Explicitly set a mode to run in. This will override the default mode for
|
||||
* each command, and can be overridden by the command line --mode option.
|
||||
@ -146,6 +153,8 @@ export type ResolvedConfig = Readonly<
|
||||
configFile: string | undefined
|
||||
inlineConfig: UserConfig
|
||||
root: string
|
||||
base: string
|
||||
publicDir: string
|
||||
command: 'build' | 'serve'
|
||||
mode: string
|
||||
isProduction: boolean
|
||||
@ -157,7 +166,6 @@ export type ResolvedConfig = Readonly<
|
||||
build: ResolvedBuildOptions
|
||||
assetsInclude: (file: string) => boolean
|
||||
logger: Logger
|
||||
base: string
|
||||
createResolver: (options?: {
|
||||
asSrc?: boolean
|
||||
tryIndex?: boolean | string
|
||||
@ -339,6 +347,8 @@ export async function resolveConfig(
|
||||
configFile: configFile ? normalizePath(configFile) : undefined,
|
||||
inlineConfig,
|
||||
root: resolvedRoot,
|
||||
base: BASE_URL,
|
||||
publicDir: path.resolve(resolvedRoot, config.publicDir || 'public'),
|
||||
command,
|
||||
mode,
|
||||
isProduction,
|
||||
@ -358,7 +368,6 @@ export async function resolveConfig(
|
||||
return DEFAULT_ASSETS_RE.test(file) || assetsFilter(file)
|
||||
},
|
||||
logger,
|
||||
base: BASE_URL,
|
||||
createResolver
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ export function assetPlugin(config: ResolvedConfig): Plugin {
|
||||
}
|
||||
// imports to absolute urls pointing to files in /public
|
||||
// will fail to resolve in the main resolver. handle them here.
|
||||
const publicFile = checkPublicFile(id, config.root)
|
||||
const publicFile = checkPublicFile(id, config)
|
||||
if (publicFile) {
|
||||
return id
|
||||
}
|
||||
@ -43,7 +43,7 @@ export function assetPlugin(config: ResolvedConfig): Plugin {
|
||||
|
||||
// raw requests, read from disk
|
||||
if (/(\?|&)raw\b/.test(id)) {
|
||||
const file = checkPublicFile(id, config.root) || cleanUrl(id)
|
||||
const file = checkPublicFile(id, config) || cleanUrl(id)
|
||||
// raw query, read file and return as string
|
||||
return `export default ${JSON.stringify(
|
||||
await fsp.readFile(file, 'utf-8')
|
||||
@ -100,13 +100,16 @@ export function assetPlugin(config: ResolvedConfig): Plugin {
|
||||
}
|
||||
}
|
||||
|
||||
export function checkPublicFile(url: string, root: string): string | undefined {
|
||||
export function checkPublicFile(
|
||||
url: string,
|
||||
{ publicDir }: ResolvedConfig
|
||||
): string | undefined {
|
||||
// note if the file is in /public, the resolver would have returned it
|
||||
// as-is so it's not going to be a fully resolved path.
|
||||
if (!url.startsWith('/')) {
|
||||
return
|
||||
}
|
||||
const publicFile = path.posix.join(root, 'public', cleanUrl(url))
|
||||
const publicFile = path.join(publicDir, cleanUrl(url))
|
||||
if (fs.existsSync(publicFile)) {
|
||||
return publicFile
|
||||
} else {
|
||||
@ -126,20 +129,20 @@ export function fileToUrl(
|
||||
}
|
||||
}
|
||||
|
||||
function fileToDevUrl(id: string, { root, base }: ResolvedConfig) {
|
||||
function fileToDevUrl(id: string, config: ResolvedConfig) {
|
||||
let rtn: string
|
||||
if (checkPublicFile(id, root)) {
|
||||
if (checkPublicFile(id, config)) {
|
||||
// in public dir, keep the url as-is
|
||||
rtn = id
|
||||
} else if (id.startsWith(root)) {
|
||||
} else if (id.startsWith(config.root)) {
|
||||
// in project root, infer short public path
|
||||
rtn = '/' + path.posix.relative(root, id)
|
||||
rtn = '/' + path.posix.relative(config.root, id)
|
||||
} else {
|
||||
// outside of project root, use absolute fs path
|
||||
// (this is special handled by the serve static middleware
|
||||
rtn = path.posix.join(FS_PREFIX + id)
|
||||
}
|
||||
return base + rtn.replace(/^\//, '')
|
||||
return config.base + rtn.replace(/^\//, '')
|
||||
}
|
||||
|
||||
const assetCache = new WeakMap<ResolvedConfig, Map<string, string>>()
|
||||
@ -154,7 +157,7 @@ async function fileToBuiltUrl(
|
||||
pluginContext: PluginContext,
|
||||
skipPublicCheck = false
|
||||
): Promise<string> {
|
||||
if (!skipPublicCheck && checkPublicFile(id, config.root)) {
|
||||
if (!skipPublicCheck && checkPublicFile(id, config)) {
|
||||
return config.base + id.slice(1)
|
||||
}
|
||||
|
||||
@ -206,7 +209,7 @@ export async function urlToBuiltUrl(
|
||||
config: ResolvedConfig,
|
||||
pluginContext: PluginContext
|
||||
): Promise<string> {
|
||||
if (checkPublicFile(url, config.root)) {
|
||||
if (checkPublicFile(url, config)) {
|
||||
return config.base + url.slice(1)
|
||||
}
|
||||
const file = url.startsWith('/')
|
||||
|
@ -126,7 +126,7 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin {
|
||||
const [preHooks, postHooks] = resolveHtmlTransforms(config.plugins)
|
||||
const processedHtml = new Map<string, string>()
|
||||
const isExcludedUrl = (url: string) =>
|
||||
isExternalUrl(url) || isDataUrl(url) || checkPublicFile(url, config.root)
|
||||
isExternalUrl(url) || isDataUrl(url) || checkPublicFile(url, config)
|
||||
|
||||
return {
|
||||
name: 'vite:build-html',
|
||||
@ -154,7 +154,7 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin {
|
||||
const { src, isModule } = getScriptInfo(node)
|
||||
|
||||
const url = src && src.value && src.value.content
|
||||
if (url && checkPublicFile(url, config.root)) {
|
||||
if (url && checkPublicFile(url, config)) {
|
||||
// referencing public dir url, prefix with base
|
||||
s.overwrite(
|
||||
src!.value!.loc.start.offset,
|
||||
@ -197,7 +197,7 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin {
|
||||
} else {
|
||||
assetUrls.push(p)
|
||||
}
|
||||
} else if (checkPublicFile(url, config.root)) {
|
||||
} else if (checkPublicFile(url, config)) {
|
||||
s.overwrite(
|
||||
p.value.loc.start.offset,
|
||||
p.value.loc.end.offset,
|
||||
|
@ -341,7 +341,7 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
|
||||
url.startsWith('/') &&
|
||||
!config.assetsInclude(cleanUrl(url)) &&
|
||||
!url.endsWith('.json') &&
|
||||
checkPublicFile(url, config.root)
|
||||
checkPublicFile(url, config)
|
||||
) {
|
||||
throw new Error(
|
||||
`Cannot import non-asset file ${url} which is inside /public.` +
|
||||
|
@ -399,7 +399,7 @@ export async function createServer(
|
||||
// serve static files under /public
|
||||
// this applies before the transform middleware so that these files are served
|
||||
// as-is without transforms.
|
||||
middlewares.use(servePublicMiddleware(path.join(root, 'public')))
|
||||
middlewares.use(servePublicMiddleware(config.publicDir))
|
||||
|
||||
// main transform middleware
|
||||
middlewares.use(transformMiddleware(server))
|
||||
|
@ -34,15 +34,11 @@ export interface TransformOptions {
|
||||
|
||||
export async function transformRequest(
|
||||
url: string,
|
||||
{
|
||||
config: { root, logger },
|
||||
pluginContainer,
|
||||
moduleGraph,
|
||||
watcher
|
||||
}: ViteDevServer,
|
||||
{ config, pluginContainer, moduleGraph, watcher }: ViteDevServer,
|
||||
options: TransformOptions = {}
|
||||
): Promise<TransformResult | null> {
|
||||
url = removeTimestampQuery(url)
|
||||
const { root, logger } = config
|
||||
const prettyUrl = isDebug ? prettifyUrl(url, root) : ''
|
||||
const ssr = !!options.ssr
|
||||
|
||||
@ -99,7 +95,7 @@ export async function transformRequest(
|
||||
}
|
||||
}
|
||||
if (code == null) {
|
||||
if (checkPublicFile(url, root)) {
|
||||
if (checkPublicFile(url, config)) {
|
||||
throw new Error(
|
||||
`Failed to load url ${url} (resolved id: ${id}). ` +
|
||||
`This file is in /public and will be copied as-is during build without ` +
|
||||
|
Loading…
Reference in New Issue
Block a user