468 lines
14 KiB
JavaScript
468 lines
14 KiB
JavaScript
'use strict';
|
|
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
|
var node_fs = require('node:fs');
|
|
var node_path = require('node:path');
|
|
var node_module = require('node:module');
|
|
var vite = require('vite');
|
|
var importTransformation = require('quasar/dist/transforms/import-transformation.js');
|
|
|
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
|
|
var importTransformation__default = /*#__PURE__*/_interopDefaultLegacy(importTransformation);
|
|
|
|
const require$1 = node_module.createRequire((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
|
|
const quasarPath = node_path.dirname(require$1.resolve('quasar/package.json'));
|
|
|
|
const { version } = JSON.parse(
|
|
node_fs.readFileSync(node_path.join(quasarPath, 'package.json'), 'utf-8')
|
|
);
|
|
|
|
function getViteConfig (runMode, viteMode, externalViteCfg) {
|
|
const viteCfg = {
|
|
define: {
|
|
__QUASAR_VERSION__: `'${ version }'`,
|
|
__QUASAR_SSR__: false,
|
|
__QUASAR_SSR_SERVER__: false,
|
|
__QUASAR_SSR_CLIENT__: false
|
|
}
|
|
};
|
|
|
|
// Set this to the default value only if it's not already set.
|
|
// @quasar/app-vite configures this by itself when it needs it.
|
|
if (!externalViteCfg.define || externalViteCfg.define.__QUASAR_SSR_PWA__ === void 0) {
|
|
viteCfg.define.__QUASAR_SSR_PWA__ = false;
|
|
}
|
|
|
|
if (runMode === 'ssr-server') {
|
|
Object.assign(viteCfg.define, {
|
|
__QUASAR_SSR__: true,
|
|
__QUASAR_SSR_SERVER__: true
|
|
});
|
|
}
|
|
else {
|
|
// Alias "quasar" package to its dev file (which has flags)
|
|
// to reduce the number of HTTP requests while in DEV mode
|
|
if (viteMode !== 'production') {
|
|
viteCfg.resolve = {
|
|
alias: [
|
|
{ find: /^quasar$/, replacement: 'quasar/dist/quasar.esm.js' }
|
|
]
|
|
};
|
|
}
|
|
else {
|
|
viteCfg.optimizeDeps = {
|
|
exclude: [ 'quasar' ]
|
|
};
|
|
}
|
|
|
|
if (runMode === 'ssr-client') {
|
|
Object.assign(viteCfg.define, {
|
|
__QUASAR_SSR__: true,
|
|
__QUASAR_SSR_CLIENT__: true
|
|
});
|
|
}
|
|
}
|
|
|
|
return viteCfg
|
|
}
|
|
|
|
const importQuasarRegex = /import\s*\{([\w,\s]+)\}\s*from\s*(['"])quasar\2;?/g;
|
|
|
|
/**
|
|
* Transforms JS code where importing from 'quasar' package
|
|
* Example:
|
|
* import { QBtn } from 'quasar'
|
|
* -> import QBtn from 'quasar/src/components/QBtn.js'
|
|
*/
|
|
function mapQuasarImports (code, importMap = {}) {
|
|
return code.replace(
|
|
importQuasarRegex,
|
|
(_, match) => match
|
|
.split(',')
|
|
.map(identifier => {
|
|
const data = identifier.split(' as ');
|
|
const importName = data[ 0 ].trim();
|
|
|
|
// might be an empty entry like below
|
|
// (notice useQuasar is followed by a comma)
|
|
// import { QTable, useQuasar, } from 'quasar'
|
|
if (importName === '') {
|
|
return ''
|
|
}
|
|
|
|
const importAs = data[ 1 ] !== void 0
|
|
? data[ 1 ].trim()
|
|
: importName;
|
|
|
|
importMap[ importName ] = importAs;
|
|
return `import ${ importAs } from '${ importTransformation__default["default"](importName) }';`
|
|
})
|
|
.join('')
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Transforms JS code where importing from 'quasar' package
|
|
* Example:
|
|
* import { QBtn } from 'quasar'
|
|
* -> add to importMap & importList & remove original import statement
|
|
* (removing original is required so that the end file will have
|
|
* only one import from Quasar statement)
|
|
*/
|
|
function removeQuasarImports (code, importMap, importSet, reverseMap) {
|
|
return code.replace(
|
|
importQuasarRegex,
|
|
(_, match) => {
|
|
match.split(',').forEach(identifier => {
|
|
const data = identifier.split(' as ');
|
|
const importName = data[ 0 ].trim();
|
|
|
|
// might be an empty entry like below
|
|
// (notice useQuasar is followed by a comma)
|
|
// import { QTable, useQuasar, } from 'quasar'
|
|
if (importName !== '') {
|
|
const importAs = data[ 1 ] !== void 0
|
|
? data[ 1 ].trim()
|
|
: importName;
|
|
|
|
importSet.add(importName + (importAs !== importName ? ` as ${ importAs }` : ''));
|
|
importMap[ importName ] = importAs;
|
|
reverseMap[ importName.replace(/-/g, '_') ] = importAs;
|
|
}
|
|
});
|
|
|
|
// we registered the original import and we
|
|
// remove this one to avoid duplicate imports from Quasar
|
|
return ''
|
|
}
|
|
)
|
|
}
|
|
|
|
const autoImportData = JSON.parse(
|
|
node_fs.readFileSync(node_path.join(quasarPath, 'dist/transforms/auto-import.json'), 'utf-8')
|
|
);
|
|
|
|
const compRegex = {
|
|
kebab: new RegExp(`_resolveComponent\\("${ autoImportData.regex.kebabComponents }"\\)`, 'g'),
|
|
pascal: new RegExp(`_resolveComponent\\("${ autoImportData.regex.pascalComponents }"\\)`, 'g'),
|
|
combined: new RegExp(`_resolveComponent\\("${ autoImportData.regex.components }"\\)`, 'g')
|
|
};
|
|
|
|
const dirRegex = new RegExp(`_resolveDirective\\("${ autoImportData.regex.directives.replace(/v-/g, '') }"\\)`, 'g');
|
|
const lengthSortFn = (a, b) => b.length - a.length;
|
|
|
|
function vueTransform (content, autoImportComponentCase, useTreeshaking) {
|
|
const importSet = new Set();
|
|
const importMap = {};
|
|
|
|
const compList = [];
|
|
const dirList = [];
|
|
|
|
const reverseMap = {};
|
|
const jsImportTransformed = useTreeshaking === true
|
|
? mapQuasarImports(content, importMap)
|
|
: removeQuasarImports(content, importMap, importSet, reverseMap);
|
|
|
|
let code = jsImportTransformed
|
|
.replace(compRegex[ autoImportComponentCase ], (_, match) => {
|
|
const name = autoImportData.importName[ match ];
|
|
const reverseName = match.replace(/-/g, '_');
|
|
|
|
if (importMap[ name ] === void 0) {
|
|
importSet.add(name);
|
|
reverseMap[ reverseName ] = name;
|
|
}
|
|
else {
|
|
reverseMap[ reverseName ] = importMap[ name ];
|
|
}
|
|
|
|
compList.push(reverseName);
|
|
return ''
|
|
})
|
|
.replace(dirRegex, (_, match) => {
|
|
const name = autoImportData.importName[ 'v-' + match ];
|
|
const reverseName = match.replace(/-/g, '_');
|
|
|
|
if (importMap[ name ] === void 0) {
|
|
importSet.add(name);
|
|
reverseMap[ reverseName ] = name;
|
|
}
|
|
else {
|
|
reverseMap[ reverseName ] = importMap[ name ];
|
|
}
|
|
|
|
dirList.push(reverseName);
|
|
return ''
|
|
});
|
|
|
|
if (compList.length !== 0) {
|
|
const list = compList.sort(lengthSortFn).join('|');
|
|
code = code
|
|
.replace(new RegExp(`const _component_(${ list }) = `, 'g'), '')
|
|
.replace(new RegExp(`_component_(${ list })`, 'g'), (_, match) => reverseMap[ match ]);
|
|
}
|
|
|
|
if (dirList.length !== 0) {
|
|
const list = dirList.sort(lengthSortFn).join('|');
|
|
code = code
|
|
.replace(new RegExp(`const _directive_(${ list }) = `, 'g'), '')
|
|
.replace(new RegExp(`_directive_(${ list })`, 'g'), (_, match) => reverseMap[ match ]);
|
|
}
|
|
|
|
if (importSet.size === 0) {
|
|
return code
|
|
}
|
|
|
|
const importList = [ ...importSet ];
|
|
const codePrefix = useTreeshaking === true
|
|
? importList.map(name => `import ${ name } from '${ importTransformation__default["default"](name) }'`).join(';')
|
|
: `import {${ importList.join(',') }} from 'quasar'`;
|
|
|
|
return codePrefix + ';' + code
|
|
}
|
|
|
|
function createScssTransform (fileExtension, sassVariables) {
|
|
const sassImportCode = [ '@import \'quasar/src/css/variables.sass\'', '' ];
|
|
|
|
if (typeof sassVariables === 'string') {
|
|
sassImportCode.unshift(`@import '${ sassVariables }'`);
|
|
}
|
|
|
|
const prefix = fileExtension === 'sass'
|
|
? sassImportCode.join('\n')
|
|
: sassImportCode.join(';\n');
|
|
|
|
return content => {
|
|
const useIndex = Math.max(
|
|
content.lastIndexOf('@use '),
|
|
content.lastIndexOf('@forward ')
|
|
);
|
|
|
|
if (useIndex === -1) {
|
|
return prefix + content
|
|
}
|
|
|
|
const newLineIndex = content.indexOf('\n', useIndex);
|
|
|
|
if (newLineIndex !== -1) {
|
|
const index = newLineIndex + 1;
|
|
return content.substring(0, index) + prefix + content.substring(index)
|
|
}
|
|
|
|
return content + '\n' + prefix
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @typedef {{
|
|
* vue: () => boolean;
|
|
* template: () => boolean;
|
|
* script: (extensions?: string | string[]) => boolean;
|
|
* style: (extensions?: string | string[]) => boolean;
|
|
* }} ViteQueryIs
|
|
*/
|
|
|
|
/**
|
|
* @see https://github.com/vitejs/vite/blob/364aae13f0826169e8b1c5db41ac6b5bb2756958/packages/plugin-vue/src/utils/query.ts - source of inspiration
|
|
* @example
|
|
* '/absolute/path/src/App.vue' // Can contain combined template&script -> template: true, script: true, style: false
|
|
* '/absolute/path/src/App.vue?vue&type=script&lang.js' // Only contains script -> template: false, script: true, style: false
|
|
* '/absolute/path/src/App.vue?vue&type=style&lang.sass' // Only contains style -> template: false, script: false, style: true
|
|
* '/absolute/path/src/script.js' // Only contains script -> template: false, script: true, style: false
|
|
* '/absolute/path/src/index.scss' // Only contains style -> template: false, script: false, style: true
|
|
*
|
|
* @param {string} id
|
|
* @returns {{ filename: string; query: { [key: string]: string; }; is: ViteQueryIs }}
|
|
*/
|
|
function parseViteRequest (id) {
|
|
const [ filename, rawQuery ] = id.split('?', 2);
|
|
const query = Object.fromEntries(new URLSearchParams(rawQuery));
|
|
|
|
const is = query.raw !== void 0
|
|
? {
|
|
// if it's a ?raw request, then don't touch it at all
|
|
vue: () => false,
|
|
template: () => false,
|
|
script: () => false,
|
|
style: () => false
|
|
}
|
|
: (
|
|
query.vue !== void 0 // is vue query?
|
|
? {
|
|
// Almost all code might get merged into a single request with no 'type' (App.vue?vue)
|
|
// or stay with their original 'type's (App.vue?vue&type=script&lang.ts)
|
|
vue: () => true,
|
|
|
|
template: () => (
|
|
query.type === void 0
|
|
|| query.type === 'template'
|
|
// On prod, TS code turns into a separate 'script' request.
|
|
// See: https://github.com/vitejs/vite/pull/7909
|
|
|| (query.type === 'script' && (query[ 'lang.ts' ] !== void 0 || query[ 'lang.tsx' ] !== void 0))
|
|
),
|
|
|
|
script: (extensions = scriptExt) => (
|
|
(query.type === void 0 || query.type === 'script')
|
|
&& isOfExt({ query, extensions }) === true
|
|
),
|
|
|
|
style: (extensions = styleExt) => (
|
|
query.type === 'style'
|
|
&& isOfExt({ query, extensions }) === true
|
|
)
|
|
}
|
|
: {
|
|
vue: () => isOfExt({ extensions: vueExt, filename }),
|
|
template: () => isOfExt({ filename, extensions: vueExt }),
|
|
script: (extensions = scriptExt) => isOfExt({ filename, extensions }),
|
|
style: (extensions = styleExt) => isOfExt({ filename, extensions })
|
|
}
|
|
);
|
|
|
|
return {
|
|
filename,
|
|
query,
|
|
is
|
|
}
|
|
}
|
|
|
|
const vueExt = [ '.vue' ];
|
|
const scriptExt = [ '.js', '.jsx', '.ts', '.tsx', '.vue' ];
|
|
const styleExt = [ '.css', '.scss', '.module.scss', '.sass', '.module.sass' ];
|
|
|
|
const isOfExt = ({ extensions, filename, query }) =>
|
|
extensions.some(
|
|
ext => filename?.endsWith(ext) || query?.[ `lang${ ext }` ] !== void 0
|
|
);
|
|
|
|
const defaultOptions = {
|
|
runMode: 'web-client',
|
|
autoImportComponentCase: 'kebab',
|
|
sassVariables: true,
|
|
devTreeshaking: false
|
|
};
|
|
|
|
function getConfigPlugin (opts) {
|
|
return {
|
|
name: 'vite:quasar:vite-conf',
|
|
|
|
configResolved (viteConf) {
|
|
const vueCfg = viteConf.plugins.find(entry => entry.name === 'vite:vue');
|
|
|
|
if (vueCfg === void 0) {
|
|
console.error('\n\n[Quasar] Error: In your Vite config file, please add the Quasar plugin ** after ** the Vue one\n\n');
|
|
process.exit(1);
|
|
}
|
|
},
|
|
|
|
config (viteConf, { mode }) {
|
|
return getViteConfig(opts.runMode, mode, viteConf)
|
|
}
|
|
}
|
|
}
|
|
|
|
function getScssTransformsPlugin (opts) {
|
|
const sassVariables = typeof opts.sassVariables === 'string'
|
|
? vite.normalizePath(opts.sassVariables)
|
|
: opts.sassVariables;
|
|
|
|
const scssTransform = createScssTransform('scss', sassVariables);
|
|
const sassTransform = createScssTransform('sass', sassVariables);
|
|
const scssExt = [ '.scss', '.module.scss' ];
|
|
const sassExt = [ '.sass', '.module.sass' ];
|
|
|
|
return {
|
|
name: 'vite:quasar:scss',
|
|
|
|
enforce: 'pre',
|
|
|
|
transform (src, id) {
|
|
const { is } = parseViteRequest(id);
|
|
|
|
if (is.style(scssExt) === true) {
|
|
return {
|
|
code: scssTransform(src),
|
|
map: null
|
|
}
|
|
}
|
|
|
|
if (is.style(sassExt) === true) {
|
|
return {
|
|
code: sassTransform(src),
|
|
map: null
|
|
}
|
|
}
|
|
|
|
return null
|
|
}
|
|
}
|
|
}
|
|
|
|
function getScriptTransformsPlugin (opts) {
|
|
let useTreeshaking = true;
|
|
|
|
return {
|
|
name: 'vite:quasar:script',
|
|
|
|
configResolved (resolvedConfig) {
|
|
if (opts.devTreeshaking === false && resolvedConfig.mode !== 'production') {
|
|
useTreeshaking = false;
|
|
}
|
|
},
|
|
|
|
transform (src, id) {
|
|
const { is } = parseViteRequest(id);
|
|
|
|
if (is.template() === true) {
|
|
return {
|
|
code: vueTransform(src, opts.autoImportComponentCase, useTreeshaking),
|
|
map: null // provide source map if available
|
|
}
|
|
}
|
|
|
|
if (useTreeshaking === true && is.script() === true) {
|
|
return {
|
|
code: mapQuasarImports(src),
|
|
map: null // provide source map if available
|
|
}
|
|
}
|
|
|
|
return null
|
|
}
|
|
}
|
|
}
|
|
|
|
function plugin (userOpts = {}) {
|
|
const opts = {
|
|
...defaultOptions,
|
|
...userOpts
|
|
};
|
|
|
|
const plugins = [
|
|
getConfigPlugin(opts)
|
|
];
|
|
|
|
if (opts.sassVariables) {
|
|
plugins.push(
|
|
getScssTransformsPlugin(opts)
|
|
);
|
|
}
|
|
|
|
if (opts.runMode !== 'ssr-server') {
|
|
plugins.push(
|
|
getScriptTransformsPlugin(opts)
|
|
);
|
|
}
|
|
|
|
return plugins
|
|
}
|
|
|
|
const transformAssetUrls = JSON.parse(
|
|
node_fs.readFileSync(node_path.join(quasarPath, 'dist/transforms/loader-asset-urls.json'), 'utf-8')
|
|
);
|
|
|
|
exports.quasar = plugin;
|
|
exports.transformAssetUrls = transformAssetUrls;
|