From 1e7fa2cf468b6891bf6d9be85c013b3e21976c7c Mon Sep 17 00:00:00 2001 From: Evan You Date: Wed, 15 Aug 2018 15:42:27 -0400 Subject: [PATCH] fix: fix css output location for relative baseUrl + more details in docs --- docs/config/README.md | 20 +++++++++++-------- docs/guide/deployment.md | 2 +- docs/zh/config/README.md | 20 +++++++++++-------- .../cli-service/lib/commands/build/index.js | 12 ----------- packages/@vue/cli-service/lib/config/css.js | 14 +++++++++++-- .../@vue/cli-service/lib/util/getAssetPath.js | 9 --------- 6 files changed, 37 insertions(+), 40 deletions(-) diff --git a/docs/config/README.md b/docs/config/README.md index f7b0cf64e..d5066f4db 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -34,9 +34,19 @@ module.exports = { - Type: `string` - Default: `'/'` - The base URL your application will be deployed at. By default Vue CLI assumes your app will be deployed at the root of a domain, e.g. `https://www.my-app.com/`. If your app is deployed at a sub-path, you will need to specify that sub-path using this option. For example, if your app is deployed at `https://www.foobar.com/my-app/`, set `baseUrl` to `'/my-app/'`. + The base URL your application bundle will be deployed at. This is the equivalent of webpack's `output.publicPath`, but Vue CLI also needs this value for other purposes, so you should **always use `baseUrl` instead of modifying webpack `output.publicPath`**. - Setting this value correctly is necessary for your static assets to be loaded properly in production. + By default, Vue CLI assumes your app will be deployed at the root of a domain, e.g. `https://www.my-app.com/`. If your app is deployed at a sub-path, you will need to specify that sub-path using this option. For example, if your app is deployed at `https://www.foobar.com/my-app/`, set `baseUrl` to `'/my-app/'`. + + The value can also be set to an empty string (`''`) or a relative path (`./`) so that all assets are linked using relative paths. This allows the built bundle to be deployed under any public path, or used in a file system based environment like a Cordova hybrid app. + + ::: warning Limitations of relative baseUrl + Relative `baseUrl` has some limitations and should be avoided when: + + - You are using HTML5 `history.pushState` routing; + + - You are using the `pages` option to build a multi-paged app. + ::: This value is also respected during development. If you want your dev server to be served at root instead, you can use a conditional value: @@ -48,12 +58,6 @@ module.exports = { } ``` - The value can also be set to an empty string (`''`) so that all assets are linked using relative paths, so that the bundle can be used in a file system based environment like a Cordova hybrid app. **Note that this will force the generated CSS files to always be placed at the root of the output directory to ensure urls in your CSS work correctly.** - - ::: tip - Always use `baseUrl` instead of modifying webpack `output.publicPath`. - ::: - ### outputDir - Type: `string` diff --git a/docs/guide/deployment.md b/docs/guide/deployment.md index 00f0a3d90..052aafa29 100644 --- a/docs/guide/deployment.md +++ b/docs/guide/deployment.md @@ -8,7 +8,7 @@ If you are developing your frontend app separately from your backend - i.e. your ### Previewing Locally -The `dist` directory is meant to be served by an HTTP server, so it will not work if you open `dist/index.html` directly over `file://` protocol. The easiest way to preview your production build locally is using a Node.js static file server, for example [serve](https://github.com/zeit/serve): +The `dist` directory is meant to be served by an HTTP server (unless you've configured `baseUrl` to be a relative value), so it will not work if you open `dist/index.html` directly over `file://` protocol. The easiest way to preview your production build locally is using a Node.js static file server, for example [serve](https://github.com/zeit/serve): ``` bash npm install -g serve diff --git a/docs/zh/config/README.md b/docs/zh/config/README.md index f552676dc..e5a5550ae 100644 --- a/docs/zh/config/README.md +++ b/docs/zh/config/README.md @@ -32,9 +32,19 @@ module.exports = { - Type: `string` - Default: `'/'` - 部署应用时的基本 URL。默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上,例如 `https://www.my-app.com/`。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 `https://www.my-app.com/my-app/`,则设置 `baseUrl` 为 `/my-app/`。 + 部署应用时的基本 URL。用法和 webpack 本身的 `output.publicPath` 一致,但是 Vue CLI 在一些其他地方也需要用到这个值,所以**请始终使用 `baseUrl` 而不要直接修改 webpack 的 `output.publicPath`**。 - 你必须正确地设置这个值以使生产环境中静态资源加载正确。 + 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上,例如 `https://www.my-app.com/`。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 `https://www.my-app.com/my-app/`,则设置 `baseUrl` 为 `/my-app/`。 + + 这个值也可以被设置为空字符串 (`''`) 或是相对路径 (`'./'`),这样所有的资源都会被链接为相对路径,这样打出来的包可以被部署在任意路径,也可以用在类似 Cordova hybrid 应用的文件系统中。 + + ::: warning 相对 baseUrl 的限制 + 相对路径的 `baseUrl` 有一些使用上的限制。在以下情况下,应当避免使用相对 `baseUrl`: + + - 当使用基于 HTML5 `history.pushState` 的路由时; + + - 当使用 `pages` 选项构建多页面应用时。 + ::: 这个值在开发环境下同样生效。如果你想把开发服务器架设在根路径,你可以使用一个条件式的值: @@ -46,12 +56,6 @@ module.exports = { } ``` - 这个值也可以被设置为空字符串 (`''`) 这样所有的资源都会被链接为相对路径,这样打出来的包可以用在类似 Cordova hybrid 应用的文件系统中。**注意:生成的 CSS 文件要始终放在输出路径的根部,以确保 CSS 中的 URL 正常工作。** - - ::: tip 提示 - 请始终使用 `baseUrl` 而不要修改 webpack 的 `output.publicPath`。 - ::: - ### outputDir - Type: `string` diff --git a/packages/@vue/cli-service/lib/commands/build/index.js b/packages/@vue/cli-service/lib/commands/build/index.js index 227a83f54..7a221fd86 100644 --- a/packages/@vue/cli-service/lib/commands/build/index.js +++ b/packages/@vue/cli-service/lib/commands/build/index.js @@ -175,7 +175,6 @@ async function build (args, api, options) { } return new Promise((resolve, reject) => { - const isFreshBuild = !fs.existsSync(api.resolve('node_modules/.cache')) webpack(webpackConfig, (err, stats) => { stopSpinner(false) if (err) { @@ -199,17 +198,6 @@ async function build (args, api, options) { } else { done(`Build complete. Watching for changes...`) } - if ( - options.baseUrl === '/' && - // only log the tips if this is the first build - isFreshBuild - ) { - console.log( - chalk.gray(`Tip: the directory is meant to be served by an HTTP server, and will not work if\n` + - `you open it directly over file:// protocol. To preview it locally, use an HTTP\n` + - `server like the ${chalk.yellow(`serve`)} package on npm.\n`) - ) - } } } diff --git a/packages/@vue/cli-service/lib/config/css.js b/packages/@vue/cli-service/lib/config/css.js index ff7ecace4..ea91e6da0 100644 --- a/packages/@vue/cli-service/lib/config/css.js +++ b/packages/@vue/cli-service/lib/config/css.js @@ -25,14 +25,21 @@ module.exports = (api, options) => { const shouldExtract = extract !== false && !shadowMode const filename = getAssetPath( options, - `css/[name]${options.filenameHashing ? '.[contenthash:8]' : ''}.css`, - true /* placeAtRootIfRelative */ + `css/[name]${options.filenameHashing ? '.[contenthash:8]' : ''}.css` ) const extractOptions = Object.assign({ filename, chunkFilename: filename }, extract && typeof extract === 'object' ? extract : {}) + // use relative publicPath in extracted CSS based on extract location + const cssPublicPath = '../'.repeat( + extractOptions.filename + .replace(/^\.[\/\\]/, '') + .split(/[\/\\]/g) + .length - 1 + ) + // check if the project has a valid postcss config // if it doesn't, don't use postcss-loader for direct style imports // because otherwise it would throw error when attempting to load postcss config @@ -68,6 +75,9 @@ module.exports = (api, options) => { rule .use('extract-css-loader') .loader(require('mini-css-extract-plugin').loader) + .options({ + publicPath: cssPublicPath + }) } else { rule .use('vue-style-loader') diff --git a/packages/@vue/cli-service/lib/util/getAssetPath.js b/packages/@vue/cli-service/lib/util/getAssetPath.js index 478a5e473..86ecea32f 100644 --- a/packages/@vue/cli-service/lib/util/getAssetPath.js +++ b/packages/@vue/cli-service/lib/util/getAssetPath.js @@ -1,15 +1,6 @@ const path = require('path') module.exports = function getAssetPath (options, filePath, placeAtRootIfRelative) { - // if the user is using a relative URL, place js & css at dist root to ensure - // relative paths work properly - if ( - placeAtRootIfRelative && - !(/^https?:/.test(options.baseUrl)) && - options.baseUrl.charAt(0) !== '/' - ) { - return filePath.replace(/^\w+\//, '') - } return options.assetsDir ? path.posix.join(options.assetsDir, filePath) : filePath