为什么捐赠
API 浏览器
联系站长
Quasar CLI with Webpack - @quasar/app-webpack
配置 quasar.config 文件

Quasar 在构建和调试时依赖诸多优秀的底层工具,例如 Webpack。Quasar 的一大优势就是为你封装并处理了这些工具的复杂配置,因此即便你不熟悉 Webpack 或其他开发工具,也能顺利使用 Quasar。

那么可以通过 /quasar.config 文件配置哪些内容?主要包括:

TIP

修改这些设置无需手动重启开发服务器。Quasar 会自动检测变化并重新加载相关进程。你不必中断开发流程,只需安心等待 Quasar CLI 快速重新加载修改后的代码,甚至还能保持当前的运行状态,大大节省你的时间!

WARNING

/quasar.config 文件由 Quasar CLI 构建系统执行,因此该文件中的代码直接运行在 Node.js 环境中,而非应用上下文中。这意味着你可以在其中引入 ‘node:fs’、‘node:path’、‘webpack’ 等模块。

结构

基础用法

/quasar.config 文件导出一个接收 ctx(上下文)参数并返回配置对象的函数。你可以根据上下文动态调整应用配置:

import { defineConfig } from '#q-app/wrappers'

export default defineConfig((ctx) => { // can be async too
  console.log(ctx)

  // Example output on console:
  {
    dev: true,
    prod: false,
    mode: { spa: true },
    modeName: 'spa',
    target: {},
    targetName: undefined,
    arch: {},
    archName: undefined,
    debug: undefined
  }

  // context gets generated based on the parameters
  // with which you run "quasar dev" or "quasar build"

  return {
    // ... your config
  }
})

举个例子,你可以仅在 PWA 模式下引入某个字体,其他模式则不引入:

{
  extras: [
    ctx.mode.pwa // we're adding only if working on a PWA
      ? "roboto-font"
      : null,
  ];
}

或者针对 SPA 模式和 Cordova 模式分别使用不同的全局 CSS 文件,其他模式则不加载:

{
  css: [
    ctx.mode.spa ? "app-spa.sass" : null, // looks for /src/css/app-spa.sass
    ctx.mode.cordova ? "app-cordova.sass" : null, // looks for /src/css/app-cordova.sass
  ];
}

还可以配置开发服务器在 SPA 模式下使用 8000 端口、PWA 模式使用 9000 端口、其他模式使用 9090 端口:

{
  devServer: {
    port: ctx.mode.spa ? 8000 : ctx.mode.pwa ? 9000 : 9090;
  }
}

也可以在返回配置前执行异步操作:

export default defineConfig(async (ctx) => {
  const data = await someAsyncFunction()
  return {
    // ... use "data"
  }
})

// or:
export default defineConfig((ctx) => {
  return new Promise(resolve => {
    // some async work then:
    // resolve() with the quasar config
    resolve({
      //
    })
  })
})

玩法无限。

IDE 自动补全

你可以使用 defineConfig() 辅助函数包裹导出的函数,以获得更好的 IDE 自动补全体验(通过 TypeScript):

import { defineConfig } from "#q-app/wrappers";

export default defineConfig((ctx) => {
  /* configuration options */
});

可配置项说明

css

/**
 * Global CSS/Stylus/SCSS/SASS/... files from `/src/css/`,
 * except for theme files, which are included by default.
 */
css?: string[];

示例:

/quasar.config file

{
  css: [
    "app.sass", // referring to /src/css/app.sass
    "~some-library/style.css", // referring to node_modules/some-library/style.css
  ];
}

vendor

默认情况下,来自 node_modules 的所有内容会被注入 vendor chunk,以优化性能和缓存。若需手动增删该 chunk 的内容,可这样配置:

/quasar.config file

return {
  vendor: {
    /* optional;
       disables vendor chunk: */ disable: true,

    add: ["src/plugins/my-special-plugin"],
    remove: ["axios", "vue$"],
  },
};

boot

更多内容请参阅 Boot 文件

/** Boot files to load. Order is important. */
boot?: QuasarBootConfiguration;

interface BootConfigurationItem {
  path: string;
  server?: false;
  client?: false;
}

type QuasarBootConfiguration = (string | BootConfigurationItem)[];

preFetch

更多内容请参阅 PreFetch 特性 页面。

/** Enable the preFetch feature. */
preFetch?: boolean;

extras

/**
 * What to import from [@quasar/extras](https://github.com/quasarframework/quasar/tree/dev/extras) package.
 * @example ['material-icons', 'roboto-font', 'ionicons-v4']
 */
extras?: (QuasarIconSets | QuasarFonts)[];

framework

告诉 CLI 要导入哪些 Quasar 组件/指令/插件、使用哪个 Quasar 国际化语言包、Quasar 组件使用什么图标集等。

仅当 “all” 设为 false 时才需要填写 “components” 和 “directives”。

/quasar.config file

framework: {
    /**
   * @see - QuasarConfOptions tab in API cards throughout the docs
   */
  config?: SerializableConfiguration<QuasarUIConfiguration>;
  /**
   * One of the Quasar IconSets
   *
   * @see https://v2.quasar.dev/options/quasar-icon-sets
   *
   * @example 'material-icons'
   */
  iconSet?: QuasarIconSets;
  /**
   * One of the Quasar language packs
   *
   * @see https://v2.quasar.dev/options/quasar-language-packs
   *
   * @example 'en-US'
   * @example 'es'
   */
  lang?: QuasarLanguageCodes;
  /**
   * Quasar CSS addons have breakpoint aware versions of flex and spacing classes
   *
   * @see https://v2.quasar.dev/layout/grid/introduction-to-flexbox#flex-addons
   * @see https://v2.quasar.dev/style/spacing#flex-addons
   */
  cssAddon?: boolean;

  /**
   * Auto import - how to detect components in your vue files
   *   "kebab": q-carousel q-page
   *   "pascal": QCarousel QPage
   *   "combined": q-carousel QPage
   *
   * @default 'kebab'
   */
  autoImportComponentCase?: "kebab" | "pascal" | "combined";

  /**
   * Quasar will auto import components based on your usage.
   * But, in case you have a special case, you can manually specify Quasar components to be available everywhere.
   *
   * An example case would be having custom component definitions with plain string templates, inside .js or .ts files,
   * in which you are using Quasar components (e.g. q-avatar).
   *
   * Another example would be that dynamically rendering components depending on an API response or similar (e.g. in a CMS),
   * something like `<component :is="dynamicName">` where `dynamicName` is a string that matches a Quasar component name.
   *
   * @example ['QAvatar', 'QChip']
   */
  components?: (keyof QuasarComponents)[];
  /**
   * Quasar will auto import directives based on your usage.
   * But, in case you have a special case, you can manually specify Quasar directives to be available everywhere.
   *
   * An example case would be having custom component definitions with plain string templates, inside .js or .ts files,
   * in which you are using Quasar directives (e.g. v-intersection).
   *
   * @example ['Intersection', 'Mutation']
   */
  directives?: (keyof QuasarDirectives)[];
  /**
   * Quasar plugins to be installed. Specify the ones you are using in your app.
   *
   * @example ['Notify', 'Loading', 'Meta', 'AppFullscreen']
   */
  plugins?: (keyof QuasarPlugins)[];
}

更多参考:

animations

更多内容请参阅 CSS 动画

/**
 * What Quasar CSS animations to import.
 * @example [ 'bounceInLeft', 'bounceOutRight' ]
 * */
animations?: QuasarAnimationsConfiguration | 'all';

devServer

Webpack devServer 选项。完整选项列表请参阅 官方文档。Quasar CLI 会根据 “quasar dev” 的参数和 Quasar 模式自动覆盖部分选项以确保配置正确。注意:如果你在代理开发服务器(比如使用云端 IDE 或本地隧道),需要在 client 部分设置 webSocketURL 为你的公网应用 URL,以保证热重载和模块热替换等功能正常工作,详见此处

常用属性:

属性类型说明
portNumber开发服务器端口
hostString开发服务器使用的本地 IP/主机名
openBoolean/Object除非设为 false,Quasar 会自动打开浏览器访问开发服务器地址。适用于 SPA、PWA 和 SSR 模式。使用 open 包的参数。详见下方。
proxyObject/Array当你有独立的后端 API 开发服务器,又希望在同一域名下发送 API 请求时,代理配置会非常有用。
devMiddlewareObject传给 webpack-dev-middleware v4 的配置
serverObject在此配置 HTTPS 替代 HTTP(见下方)
onBeforeSetupMiddlewareFunction在 webpack-dev-server 应用自身配置前配置开发中间件。
onAfterSetupMiddlewareFunction在 webpack-dev-server 应用自身配置后配置开发中间件。

使用 open 属性可以指定用特定浏览器打开,而非操作系统默认浏览器(查看支持的值)。前述链接中描述的 options 参数即为 quasar.config 文件 > devServer > open 的配置项。示例:

/quasar.config file

// (syntax below requires @quasar/app-webpack v3.3+)

// opens Google Chrome
devServer: {
  open: {
    app: {
      name: "google chrome";
    }
  }
}

// opens Firefox
devServer: {
  open: {
    app: {
      name: "firefox";
    }
  }
}

// opens Google Chrome and automatically deals with cross-platform issues:
import open from "open";

devServer: {
  open: {
    app: {
      name: open.apps.chrome;
    }
  }
}

当你在 /quasar.config 文件中设置 devServer > server > type: 'https' 时,Quasar 会自动为你生成 SSL 证书。不过如果你想为 localhost 自行创建证书,可以参考 Filippo 的这篇教程。然后你的 quasar.config 文件 > devServer > server 应该类似这样:

/quasar.config file

devServer: {
  server: {
    type: 'https', // NECESSARY (alternative is type 'http')

    options: {
      // Use ABSOLUTE paths or path.join(__dirname, 'root/relative/path')
      key: "/path/to/server.key",
      pfx: "/path/to/server.pfx",
      cert: "/path/to/server.crt",
      ca: "/path/to/ca.pem",
      passphrase: 'webpack-dev-server' // do you need it?
    }
  }
}

你还可以配置自动打开远程 Vue Devtools:

/quasar.config file

devServer: {
  vueDevtools: true;
}

Docker 和 WSL 下的 HMR 问题

如果你使用 Docker 容器,可能会遇到 HMR 失效的问题。HMR 依赖操作系统发出文件变更通知,而 Docker 容器中这一机制可能无法正常工作。

一个权宜之计是启用轮询模式来检测文件系统变化。启用方式如下:

/quasar.config file

build: {
  // ...
  extendWebpack(cfg) {
    cfg.watchOptions = {
      aggregateTimeout: 200,
      poll: 1000,
    };
  },
// ...

build

/quasar.config file

build: {
  /**
   * Transpile JS code with Babel
   *
   * @default true
   */
  webpackTranspile?: boolean;
  /**
   * Add dependencies for transpiling with Babel (from node_modules, which are by default not transpiled).
   * It is ignored if "transpile" is not set to true.
   * @example [ /my-dependency/, 'my-dep', ...]
   */
  webpackTranspileDependencies?: (RegExp | string)[];
  /**
   * Esbuild is used to build contents of /src-pwa, /src-ssr, /src-electron, /src-bex
   * @example
   *    {
   *      browser: ['es2022', 'firefox115', 'chrome115', 'safari14'],
   *      node: 'node20'
   *    }
   */
  esbuildTarget?: EsbuildTargetOptions;

  /**
   * Extend Webpack config generated by Quasar CLI.
   * Equivalent to chainWebpack(), but you have direct access to the Webpack config object.
   */
  extendWebpack?: (
    config: WebpackConfiguration,
    invokeParams: InvokeParams
  ) => void;
  /**
   * Extend Webpack config generated by Quasar CLI.
   * Equivalent to extendWebpack(), but using [webpack-chain](https://github.com/sorrycc/webpack-chain) instead.
   */
  chainWebpack?: (chain: WebpackChain, invokeParams: InvokeParams) => void;

  /**
   * Prepare external services before `$ quasar dev` command runs
   * like starting some backend or any other service that the app relies on.
   * Can use async/await or directly return a Promise.
   */
  beforeDev?: (params: QuasarHookParams) => void;
  /**
   * Run hook after Quasar dev server is started (`$ quasar dev`).
   * At this point, the dev server has been started and is available should you wish to do something with it.
   * Can use async/await or directly return a Promise.
   */
  afterDev?: (params: QuasarHookParams) => void;
  /**
   * Run hook before Quasar builds app for production (`$ quasar build`).
   * At this point, the distributables folder hasn't been created yet.
   * Can use async/await or directly return a Promise.
   */
  beforeBuild?: (params: QuasarHookParams) => void;
  /**
   * Run hook after Quasar built app for production (`$ quasar build`).
   * At this point, the distributables folder has been created and is available
   *  should you wish to do something with it.
   * Can use async/await or directly return a Promise.
   */
  afterBuild?: (params: QuasarHookParams) => void;
  /**
   * Run hook if publishing was requested (`$ quasar build -P`),
   *  after Quasar built app for production and the afterBuild hook (if specified) was executed.
   * Can use async/await or directly return a Promise.
   * `opts` is Object of form `{arg, distDir}`,
   * where "arg" is the argument supplied (if any) to -P parameter.
   */
  onPublish?: (ops: { arg: string; distDir: string }) => void;

  /**
   * Public path of your app.
   * Use it when your public path is something else,
   * like _"<protocol>://<domain>/some/nested/folder"_ – in this case,
   * it means the distributables are in _"some/nested/folder"_ on your webserver.
   *
   * @default '/'
   */
  publicPath?: string;
  /**
   * @default 'index.html'
   */
  htmlFilename?: string;
  /**
   * Folder where Quasar CLI should generate the distributables.
   * Relative path to project root directory.
   *
   * @default 'dist/{ctx.modeName}' For all modes except Cordova.
   * @default 'src-cordova/www' For Cordova mode.
   */
  distDir?: string;
  /**
   * Ignores the public folder.
   */
  ignorePublicFolder?: boolean;

  /**
   * Sets [Vue Router mode](https://router.vuejs.org/guide/essentials/history-mode.html).
   * History mode requires configuration on your deployment web server too.
   * For Capacitor and Electron, it's always 'hash' for [compatibility reasons](https://github.com/quasarframework/quasar/issues/17322#issuecomment-2191987962).
   *
   * @default 'hash'
   */
  vueRouterMode?: "hash" | "history";
  /**
   * Sets Vue Router base.
   * Should not need to configure this, unless absolutely needed.
   */
  vueRouterBase?: string;
  /** Include vue runtime + compiler version, instead of default Vue runtime-only. */
  vueCompiler?: boolean;
  /**
   * Automatically open remote Vue Devtools when running in development mode.
   */
  vueDevtools?: boolean;
  /**
   * Should the Vue Options API be available? If all your components only use Composition API
   * it would make sense performance-wise to disable Vue Options API for a compile speedup.
   *
   * @default true
   */
  vueOptionsAPI?: boolean;

  /** Show a progress bar while compiling with Webpack. */
  webpackShowProgress?: boolean;
  /**
   * Source map [strategy](https://webpack.js.org/configuration/devtool/) to use.
   */
  webpackDevtool?: WebpackConfiguration["devtool"];

  /**
   * @example
   * {
   *   // import { ... } from 'locales/...'
   *   locales: path.join(__dirname, 'src/locales')
   * }
   */
  alias?: { [key: string]: string };
  /**
   * Configuration for TypeScript integration.
   */
  typescript?: {
    /**
     * Once your codebase is fully using TypeScript and all team members are comfortable with it,
     * you can set this to `true` to enforce stricter type checking.
     * It is recommended to set this to `true` and use stricter typescript-eslint rules.
     *
     * It will set the following TypeScript options:
     * - "strict": true
     * - "allowUnreachableCode": false
     * - "allowUnusedLabels": false
     * - "noImplicitOverride": true
     * - "exactOptionalPropertyTypes": true
     * - "noUncheckedIndexedAccess": true
     *
     * @see https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html#getting-stricter-checks
     */
    strict?: boolean;

    /**
     * Extend the generated `.quasar/tsconfig.json` file.
     *
     * If you don't have dynamic logic, you can directly modify your `tsconfig.json` file instead.
     */
    extendTsConfig?: (tsConfig: TSConfig) => void;

    /**
     * Generate a shim file for `*.vue` files to process them as plain Vue component instances.
     *
     * Vue Language Tools VS Code extension can analyze `*.vue` files in a better way, without the shim file.
     * So, you can disable the shim file generation and let the extension handle the types.
     *
     * However, some tools like ESLint can't work with `*.vue` files without the shim file.
     * So, if your tooling is not properly working, enable this option.
     */
    vueShim?: boolean;
  };

  /**
   * Add properties to `process.env` that you can use in your website/app JS code.
   *
   * @example { SOMETHING: 'someValue' }
   */
  env?: { [index: string]: string | boolean | undefined | null };
  /**
   * Defines constants that get replaced in your app.
   * Unlike `env`, you will need to use JSON.stringify() on the values yourself except for booleans.
   * Also, these will not be prefixed with `process.env.`.
   *
   * @example { SOMETHING: JSON.stringify('someValue') } -> console.log(SOMETHING) // console.log('someValue')
   */
  rawDefine?: { [index: string]: string | boolean | undefined | null };
  /**
   * Folder where Quasar CLI should look for .env* files.
   * Can be an absolute path or a relative path to project root directory.
   *
   * @default project root directory
   */
  envFolder?: string;
  /**
   * Additional .env* files to be loaded.
   * Each entry can be an absolute path or a relative path to quasar.config > build > envFolder.
   *
   * @example ['.env.somefile', '../.env.someotherfile']
   */
  envFiles?: string[];

  /**
   * Gzip the distributables.
   * Could be either a boolean or compression plugin options object.
   * In addition, you can specify which file extension you want to
   * gzip with extension array field in replacement of compression plugin test option.
   * By default it's ['js','css'].
   * @example
   *    {
   *      extension: ['js','css','svg'],
   *      threshold: 0,
   *      minRatio: 1
   *    }
   * @default false
   */
  gzip?:
    | boolean
    | (DefinedDefaultAlgorithmAndOptions<any> & {
        extensions: string[];
      });
  /**
   * Show analysis of build bundle with webpack-bundle-analyzer.
   * When providing an object, it represents webpack-bundle-analyzer config options.
   */
  analyze?: boolean | BundleAnalyzerPlugin.Options;

  /**
   * Minification options. [Full list](https://github.com/webpack-contrib/terser-webpack-plugin/#minify).
   */
  uglifyOptions?: TerserOptions;
  /** Options to supply to `sass-loader` for `.scss` files. */
  scssLoaderOptions?: object;
  /** Options to supply to `sass-loader` for [`.sass`](https://github.com/webpack-contrib/sass-loader#sassoptions) files. */
  sassLoaderOptions?: object;
  /** Options to supply to `stylus-loader`. */
  stylusLoaderOptions?: object;
  /** Options to supply to `less-loader`. */
  lessLoaderOptions?: object;
  /** Options to supply to `vue-loader` */
  vueLoaderOptions?: object;
  /** Options to supply to `ts-loader` */
  tsLoaderOptions?: object;
  /**
   * RTL options. [Full list](https://github.com/vkalinichev/postcss-rtl).
   * When providing an object, it is the configuration for postcss-rtl plugin, and if fromRTL is present it will only be used for client styles
   * When providing a function, the function will receive a boolean that is true for client side styles and false otherwise and the path to the style file
   *
   */
  rtl?:
    | boolean
    | object
    | ((isClientCSS: boolean, resourcePath: string) => object);

  /**
   * Set to `false` to disable minification, or specify the minifier to use.
   * Available options are 'terser' or 'esbuild'.
   * If set to anything but boolean false then it also applies to CSS.
   * For production only.
   * @default 'esbuild'
   */
  minify?: boolean | 'terser' | 'esbuild';
  /**
   * Minification options for html-minifier-terser: https://github.com/terser/html-minifier-terser?tab=readme-ov-file#options-quick-reference
   * @default
   *  {
   *    removeComments: true,
   *    collapseWhitespace: true,
   *    removeAttributeQuotes: true,
   *    collapseBooleanAttributes: true,
   *    removeScriptTypeAttributes: true
   *  }
   */
  htmlMinifyOptions?: HtmlMinifierOptions;
  /**
   * If `true`, a separate sourcemap file will be created. If 'inline', the
   * sourcemap will be appended to the resulting output file as data URI.
   * 'hidden' works like `true` except that the corresponding sourcemap
   * comments in the bundled files are suppressed.
   * @default false
   */
  sourcemap?: boolean | 'inline' | 'hidden';
}

例如,如果你运行 “quasar build --debug”,则 sourceMap 和 extractCSS 会被强制设为 “true”,不受你的配置影响。

sourceFiles

使用此属性可以修改应用中部分文件的默认名称。所有路径都必须是相对于项目根目录的相对路径。

/quasar.config file

/**
 * Use this property to change the default names of some files of your website/app if you have to.
 * All paths must be relative to the root folder of your project.
 *
 * @default
 * {
 *  rootComponent: 'src/App.vue',
 *  router: 'src/router/index',
 *  store: 'src/stores/index',
 *  indexHtmlTemplate: 'index.html',
 *  pwaRegisterServiceWorker: 'src-pwa/register-service-worker',
 *  pwaServiceWorker: 'src-pwa/custom-service-worker',
 *  pwaManifestFile: 'src-pwa/manifest.json',
 *  electronMain: 'src-electron/electron-main',
 *  bexManifestFile: 'src-bex/manifest.json'
 * }
 */
sourceFiles: {
  rootComponent?: string;
  router?: string;
  store?: string;
  indexHtmlTemplate?: string;
  pwaRegisterServiceWorker?: string;
  pwaServiceWorker?: string;
  pwaManifestFile?: string;
  electronMain?: string;
  bexManifestFile?: string;
}

htmlVariables

/** Add variables that you can use in /index.html. */
htmlVariables?: Record<string, any>;

你可以定义变量,然后在 /index.html 中引用它们,示例如下:

/quasar.config file

import { defineConfig } from "#q-app/wrappers";

export default defineConfig((ctx) => {
  return {
    htmlVariables: {
      myVar: "some-content",
    },
  };
});

然后在模板中使用:

/index.html

<%= myVar %> <% if (myVar) { %>something<% } %>

再来一个例子:

/quasar.config file

htmlVariables: {
  title: 'test name',
  some: {
    prop: 'my-prop'
  }
}

在模板中使用:

/index.html

<%= title %> <%= some.prop %> <% if (some.prop) { %><%= title %><% } %>

示例:为 dev/build 设置环境变量

请参考文档中的 添加到 process.env 章节。

深入理解 Webpack 配置

详情请参阅 处理 Webpack 配置 文档页面。