流程图

Quasar中的转字符串方法


devServer.listen()
listen () {
const cfg = this.quasarConfFile.quasarConf
const webpackConf = this.quasarConfFile.webpackConf
return new Promise(resolve => {
const compiler = webpack(webpackConf.renderer)
compiler.hooks.done.tap('done-compiling', stats => {
if (this.__started === true) { return }
if (stats.hasErrors() === true) {
return
}
this.__started = true
resolve()
if (openedBrowser === false) {
openedBrowser = true
if (cfg.__devServer.open && ['spa', 'pwa'].includes(cfg.ctx.modeName)) {
openBrowser({ url: cfg.build.APP_URL, opts: cfg.__devServer.openOptions })
}
}
})
this.server = new WebpackDevServer(cfg.devServer, compiler)
this.server.start()
})
}
cfg实例截图

goLive
async function goLive () {
if (argv.mode !== 'spa') {
const installMissing = require('../mode/install-missing')
await installMissing(argv.mode, argv.target)
}
const DevServer = argv.mode === 'ssr'
? require('../dev-server-ssr')
: require('../dev-server-regular')
const QuasarConfFile = require('../quasar-conf-file')
const Generator = require('../generator')
const getQuasarCtx = require('../helpers/get-quasar-ctx')
const extensionRunner = require('../app-extension/extensions-runner')
const regenerateTypesFeatureFlags = require('../helpers/types-feature-flags')
const ctx = getQuasarCtx({
mode: argv.mode,
target: argv.target,
emulator: argv.emulator,
dev: true,
vueDevtools: argv.devtools
})
await extensionRunner.registerExtensions(ctx)
const quasarConfFile = new QuasarConfFile(ctx, {
port: argv.port,
host: argv.hostname,
onAddress: parseAddress,
onBuildChange () {
log(`Rebuilding app...`)
dev = dev.then(startDev)
},
onAppChange () {
log(`Updating app...`)
generator.build()
}
})
try {
await quasarConfFile.prepare()
}
catch (e) {
console.log(e)
fatal('quasar.config.js has JS errors', 'FAIL')
}
await quasarConfFile.compile()
const quasarConf = quasarConfFile.quasarConf
regenerateTypesFeatureFlags(quasarConf)
if (quasarConf.__vueDevtools !== false) {
await startVueDevtools()
}
if (typeof quasarConf.build.beforeDev === 'function') {
await quasarConf.build.beforeDev({ quasarConf })
}
await extensionRunner.runHook('beforeDev', async hook => {
log(`Extension(${hook.api.extId}): Running beforeDev hook...`)
await hook.fn(hook.api, { quasarConf })
})
const generator = new Generator(quasarConfFile)
let runMode
if (['cordova', 'capacitor', 'electron', 'bex', 'pwa', 'ssr'].includes(argv.mode)) {
const ModeRunner = require('../' + (argv.mode === 'ssr' ? 'pwa' : argv.mode))
ModeRunner.init(ctx)
runMode = () => ModeRunner.run(quasarConfFile, argv)
}
else {
runMode = () => {}
}
function startDev (oldDevServer) {
let devServer
const runMain = async () => {
if (oldDevServer !== void 0) {
await oldDevServer.stop()
oldDevServer = void 0
}
generator.build()
devServer = new DevServer(quasarConfFile)
return devServer.listen()
}
let promise = Promise.resolve()
promise = quasarConfFile.ctx.mode.pwa === true
? promise.then(runMode).then(runMain)
: promise.then(runMain).then(runMode)
return promise.then(() => devServer)
}
let dev = startDev().then(async (payload) => {
if (typeof quasarConf.build.afterDev === 'function') {
await quasarConf.build.afterDev({ quasarConf })
}
await extensionRunner.runHook('afterDev', async hook => {
log(`Extension(${hook.api.extId}): Running afterDev hook...`)
await hook.fn(hook.api, { quasarConf })
})
return payload
})
}
create-chain设置WebPack配置
module.exports = function (cfg, configName) {
const chain = new WebpackChain()
const useFastHash = cfg.ctx.dev || ['electron', 'cordova', 'capacitor', 'bex'].includes(cfg.ctx.modeName)
const fileHash = useFastHash === true ? '' : '.[contenthash:8]'
const assetHash = useFastHash === true ? '.[hash:8]' : '.[contenthash:8]'
const resolveModules = [
'node_modules',
appPaths.resolve.app('node_modules'),
appPaths.resolve.cli('node_modules')
]
chain.entry('app').add(appPaths.resolve.app('.quasar/client-entry.js'))
chain.mode(cfg.ctx.dev ? 'development' : 'production')
chain.devtool(cfg.build.sourceMap ? cfg.build.devtool : false)
if (cfg.ctx.prod || cfg.ctx.mode.ssr) {
chain.output
.path(
cfg.ctx.mode.ssr
? path.join(cfg.build.distDir, 'www')
: cfg.build.distDir
)
.publicPath(cfg.build.publicPath)
.filename(`js/[name]${fileHash}.js`)
.chunkFilename(`js/[name]${useFastHash === true ? '' : '.[chunkhash:8]'}.js`)
}
chain.resolve.extensions
.merge(
cfg.supportTS !== false
? [ '.mjs', '.ts', '.js', '.vue', '.json', '.wasm' ]
: [ '.mjs', '.js', '.vue', '.json', '.wasm' ]
)
chain.resolve.modules
.merge(resolveModules)
chain.resolve.alias
.merge({
src: appPaths.srcDir,
app: appPaths.appDir,
components: appPaths.resolve.src('components'),
layouts: appPaths.resolve.src('layouts'),
pages: appPaths.resolve.src('pages'),
assets: appPaths.resolve.src('assets'),
boot: appPaths.resolve.src('boot'),
stores: appPaths.resolve.src('stores'),
'src-bex': appPaths.bexDir // needed for app/templates
})
if (extrasPath) {
// required so quasar/icon-sets/* with imports to work correctly
chain.resolve.alias.merge({ '@quasar/extras': extrasPath })
}
const vueFile = configName === webpackNames.ssr.serverSide
? (cfg.ctx.prod ? 'vue.cjs.prod.js' : 'vue.cjs.js')
: (
cfg.build.vueCompiler
? 'vue.esm-bundler.js'
: 'vue.runtime.esm-bundler.js'
)
chain.resolve.alias.set('vue$', 'vue/dist/' + vueFile)
const vueI18nFile = configName === webpackNames.ssr.serverSide
? (cfg.ctx.prod ? 'vue-i18n.cjs.prod.js' : 'vue-i18n.cjs.js')
: 'vue-i18n.esm-bundler.js'
chain.resolve.alias.set('vue-i18n$', 'vue-i18n/dist/' + vueI18nFile)
chain.resolveLoader.modules
.merge(resolveModules)
chain.module.noParse(
/^(vue|vue-router|pinia|vuex|vuex-router-sync|@quasar[\/]extras|quasar[\/]dist)$/
)
const vueRule = chain.module.rule('vue')
.test(/.vue$/)
vueRule.use('vue-auto-import-quasar')
.loader(path.join(__dirname, 'loader.vue.auto-import-quasar.js'))
.options({
autoImportComponentCase: cfg.framework.autoImportComponentCase,
isServerBuild: configName === webpackNames.ssr.serverSide
})
vueRule.use('vue-loader')
.loader('vue-loader')
.options(
merge(
{},
cfg.build.vueLoaderOptions,
{ isServerBuild: configName === webpackNames.ssr.serverSide }
)
)
if (configName !== webpackNames.ssr.serverSide) {
chain.module.rule('js-transform-quasar-imports')
.test(/.(t|j)sx?$/)
.use('transform-quasar-imports')
.loader(path.join(__dirname, 'loader.js.transform-quasar-imports.js'))
}
if (cfg.build.transpile === true) {
const nodeModulesRegex = /[\/]node_modules[\/]/
const exceptionsRegex = getDependenciesRegex(
[ /.vue.js$/, configName === webpackNames.ssr.serverSide ? 'quasar/src' : 'quasar', '@babel/runtime' ]
.concat(cfg.build.transpileDependencies)
)
chain.module.rule('babel')
.test(/.js$/)
.exclude
.add(filepath => (
// Transpile the exceptions:
exceptionsRegex.test(filepath) === false &&
// Don't transpile anything else in node_modules:
nodeModulesRegex.test(filepath)
))
.end()
.use('babel-loader')
.loader('babel-loader')
.options({
compact: false,
extends: appPaths.resolve.app('babel.config.js')
})
}
if (cfg.supportTS !== false) {
chain.module
.rule('typescript')
.test(/.ts$/)
.use('ts-loader')
.loader('ts-loader')
.options({
// custom config is merged if present, but vue setup and type checking disable are always applied
...(cfg.supportTS.tsLoaderConfig || {}),
appendTsSuffixTo: [ /.vue$/ ],
// Type checking is handled by fork-ts-checker-webpack-plugin
transpileOnly: true
})
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
chain
.plugin('ts-checker')
// https://github.com/TypeStrong/fork-ts-checker-webpack-plugin#options
.use(ForkTsCheckerWebpackPlugin, [
// custom config is merged if present, but vue option is always enabled
merge({}, cfg.supportTS.tsCheckerConfig || {}, {
typescript: {
extensions: {
vue: {
enabled: true,
compiler: '@vue/compiler-sfc'
}
}
}
})
])
}
// TODO: change to Asset Management when webpack-chain is webpack5 compatible
chain.module.rule('images')
.test(/.(png|jpe?g|gif|svg|webp|avif|ico)(?.*)?$/)
.type('javascript/auto')
.use('url-loader')
.loader('url-loader')
.options({
esModule: false,
limit: 10000,
name: `img/[name]${assetHash}.[ext]`
})
// TODO: change to Asset Management when webpack-chain is webpack5 compatible
chain.module.rule('fonts')
.test(/.(woff2?|eot|ttf|otf)(?.*)?$/)
.type('javascript/auto')
.use('url-loader')
.loader('url-loader')
.options({
esModule: false,
limit: 10000,
name: `fonts/[name]${assetHash}.[ext]`
})
// TODO: change to Asset Management when webpack-chain is webpack5 compatible
chain.module.rule('media')
.test(/.(mp4|webm|ogg|mp3|wav|flac|aac)(?.*)?$/)
.type('javascript/auto')
.use('url-loader')
.loader('url-loader')
.options({
esModule: false,
limit: 10000,
name: `media/[name]${assetHash}.[ext]`
})
injectStyleRules(chain, {
isServerBuild: configName === webpackNames.ssr.serverSide,
rtl: cfg.build.rtl,
sourceMap: cfg.build.sourceMap,
extract: cfg.build.extractCSS,
minify: cfg.build.minify,
stylusLoaderOptions: cfg.build.stylusLoaderOptions,
sassLoaderOptions: cfg.build.sassLoaderOptions,
scssLoaderOptions: cfg.build.scssLoaderOptions,
lessLoaderOptions: cfg.build.lessLoaderOptions
})
chain.module // fixes https://github.com/graphql/graphql-js/issues/1272
.rule('mjs')
.test(/.mjs$/)
.type('javascript/auto')
.include
.add(/[\/]node_modules[\/]/)
chain.plugin('vue-loader')
.use(VueLoaderPlugin)
chain.plugin('define')
.use(webpack.DefinePlugin, [
parseBuildEnv(cfg.build.env, getRootDefines(cfg.__rootDefines, configName))
])
chain.optimization
.nodeEnv(false)
if (cfg.ctx.dev && configName !== webpackNames.ssr.serverSide && cfg.ctx.mode.pwa && cfg.pwa.workboxPluginMode === 'InjectManifest') {
// need to place it here before the status plugin
const CustomSwWarningPlugin = require('./pwa/plugin.custom-sw-warning')
chain.plugin('custom-sw-warning')
.use(CustomSwWarningPlugin)
}
chain.plugin('progress')
.use(WebpackProgressPlugin, [{ name: configName, cfg }])
chain.plugin('boot-default-export')
.use(BootDefaultExport)
chain.performance
.hints(false)
.maxAssetSize(500000)
if (configName !== webpackNames.ssr.serverSide && cfg.vendor.disable !== true) {
const { add, remove } = cfg.vendor
const regex = /[\/]node_modules[\/]/
chain.optimization.splitChunks({
cacheGroups: {
defaultVendors: {
name: 'vendor',
chunks: 'all',
priority: -10,
// a module is extracted into the vendor chunk if...
test: add !== void 0 || remove !== void 0
? module => {
if (module.resource) {
if (remove !== void 0 && remove.test(module.resource)) { return false }
if (add !== void 0 && add.test(module.resource)) { return true }
}
return regex.test(module.resource)
}
: regex
},
common: {
name: `chunk-common`,
minChunks: 2,
priority: -20,
chunks: 'all',
reuseExistingChunk: true
}
}
})
}
// extract css into its own file
if (configName !== webpackNames.ssr.serverSide && cfg.build.extractCSS) {
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
chain.plugin('mini-css-extract')
.use(MiniCssExtractPlugin, [{
filename: `css/[name]${fileHash}.css`
}])
}
if (cfg.ctx.prod) {
if (
cfg.build.ignorePublicFolder !== true &&
configName !== webpackNames.ssr.serverSide
) {
// copy /public to dist folder
const CopyWebpackPlugin = require('copy-webpack-plugin')
const ignore = [
'**/.DS_Store',
'**/.Thumbs.db',
'**/*.sublime*',
'**/.idea',
'**/.editorconfig',
'**/.vscode'
]
// avoid useless files to be copied
if (['electron', 'cordova', 'capacitor'].includes(cfg.ctx.modeName)) {
ignore.push(
'**/public/icons', '**/public/favicon.ico'
)
}
const patterns = [{
from: appPaths.resolve.app('public'),
noErrorOnMissing: true,
globOptions: { ignore }
}]
chain.plugin('copy-webpack')
.use(CopyWebpackPlugin, [{ patterns }])
}
chain.optimization
.concatenateModules(cfg.ctx.mode.ssr !== true)
if (cfg.ctx.debug) {
// reset default webpack 4 minimizer
chain.optimization.minimizers.delete('js')
// also:
chain.optimization.minimize(false)
}
else if (cfg.build.minify) {
const TerserPlugin = require('terser-webpack-plugin')
chain.optimization
.minimizer('js')
.use(TerserPlugin, [{
terserOptions: cfg.build.uglifyOptions,
extractComments: false,
parallel: true
}])
}
if (configName !== webpackNames.ssr.serverSide) {
// dedupe & minify CSS (only if extracted)
if (cfg.build.extractCSS && cfg.build.minify) {
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
// We are using this plugin so that possible
// duplicated CSS = require(different components) can be deduped.
chain.optimization
.minimizer('css')
.use(CssMinimizerPlugin, [{
parallel: true
}])
}
// also produce a gzipped version
if (cfg.build.gzip) {
const CompressionWebpackPlugin = require('compression-webpack-plugin')
chain.plugin('compress-webpack')
.use(CompressionWebpackPlugin, [ cfg.build.gzip ])
}
if (cfg.build.analyze) {
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
chain.plugin('bundle-analyzer')
.use(BundleAnalyzerPlugin, [ Object.assign({}, cfg.build.analyze) ])
}
}
}
return chain
}
WebPack Chain详细信息
Overview

WebPackChain 详细信息



webpack插件
