diff --git a/packages/uni-template-compiler/lib/index.js b/packages/uni-template-compiler/lib/index.js index 258685bc80f77c6dfd58206661edd56a7c9a88f3..77f1fc3c2f8b281cc9114fe98ff92b7ff1753390 100644 --- a/packages/uni-template-compiler/lib/index.js +++ b/packages/uni-template-compiler/lib/index.js @@ -109,6 +109,17 @@ at ${resourcePath}.vue:1`) * ...暂时使用方案1 */ if (options.emitFile) { + // cache + if (process.env.UNI_USING_CACHE) { + const oldEmitFile = options.emitFile + process.UNI_CACHE_TEMPLATES = {} + options.emitFile = function emitFile (name, content) { + const absolutePath = path.resolve(process.env.UNI_OUTPUT_DIR, name) + process.UNI_CACHE_TEMPLATES[absolutePath] = content + oldEmitFile(name, content) + } + } + if (options.updateSpecialMethods) { options.updateSpecialMethods(resourcePath, [...res.specialMethods]) } diff --git a/packages/vue-cli-plugin-hbuilderx/module-alias.js b/packages/vue-cli-plugin-hbuilderx/module-alias.js index 4c32e657bf06756e54db5c67e80c248a0943ea1a..259886c16e1595d4046e9ad639dd6e2400b5320d 100644 --- a/packages/vue-cli-plugin-hbuilderx/module-alias.js +++ b/packages/vue-cli-plugin-hbuilderx/module-alias.js @@ -6,7 +6,7 @@ const { isInHBuilderX } = require('@dcloudio/uni-cli-shared') -// override +// nvue override moduleAlias.addAlias('weex-styler', path.resolve(__dirname, 'packages/weex-styler')) moduleAlias.addAlias('weex-template-compiler', path.resolve(__dirname, 'packages/weex-template-compiler')) moduleAlias.addAlias('./compileTemplate', path.resolve(__dirname, @@ -19,6 +19,14 @@ moduleAlias.addAlias('./templateLoader', (fromPath, request, alias) => { } return request }) +// vue cache +moduleAlias.addAlias('./loaders/pitcher', (fromPath, request, alias) => { + if (fromPath.indexOf('vue-loader') !== -1) { + return path.resolve(__dirname, 'packages/vue-loader/lib/loaders/pitcher') + } + return request +}) + if (isInHBuilderX) { moduleAlias.addAlias('typescript', path.resolve(process.env.UNI_HBUILDERX_PLUGINS, 'compile-typescript/node_modules/typescript')) diff --git a/packages/vue-cli-plugin-hbuilderx/packages/vue-loader/lib/loaders/pitcher.js b/packages/vue-cli-plugin-hbuilderx/packages/vue-loader/lib/loaders/pitcher.js new file mode 100644 index 0000000000000000000000000000000000000000..6af379ba75109d3d97a5e53b8ee5650c1cac28c0 --- /dev/null +++ b/packages/vue-cli-plugin-hbuilderx/packages/vue-loader/lib/loaders/pitcher.js @@ -0,0 +1,160 @@ +const qs = require('querystring') +const loaderUtils = require('loader-utils') +const hash = require('hash-sum') +const selfPath = require.resolve('vue-loader/lib/index') +const templateLoaderPath = require.resolve('vue-loader/lib/loaders/templateLoader') +const stylePostLoaderPath = require.resolve('vue-loader/lib/loaders/stylePostLoader') + +const isESLintLoader = l => /(\/|\\|@)eslint-loader/.test(l.path) +const isNullLoader = l => /(\/|\\|@)null-loader/.test(l.path) +const isCSSLoader = l => /(\/|\\|@)css-loader/.test(l.path) +const isCacheLoader = l => /(\/|\\|@)cache-loader/.test(l.path) +const isPitcher = l => l.path !== __filename +const isPreLoader = l => !l.pitchExecuted +const isPostLoader = l => l.pitchExecuted + +const dedupeESLintLoader = loaders => { + const res = [] + let seen = false + loaders.forEach(l => { + if (!isESLintLoader(l)) { + res.push(l) + } else if (!seen) { + seen = true + res.push(l) + } + }) + return res +} + +const shouldIgnoreCustomBlock = loaders => { + const actualLoaders = loaders.filter(loader => { + // vue-loader + if (loader.path === selfPath) { + return false + } + + // cache-loader + if (isCacheLoader(loader)) { + return false + } + + return true + }) + return actualLoaders.length === 0 +} + +module.exports = code => code + +// This pitching loader is responsible for intercepting all vue block requests +// and transform it into appropriate requests. +module.exports.pitch = function (remainingRequest) { + const options = loaderUtils.getOptions(this) + const { cacheDirectory, cacheIdentifier } = options + const query = qs.parse(this.resourceQuery.slice(1)) + + let loaders = this.loaders + + // if this is a language block request, eslint-loader may get matched + // multiple times + if (query.type) { + // if this is an inline block, since the whole file itself is being linted, + // remove eslint-loader to avoid duplicate linting. + if (/\.vue$/.test(this.resourcePath)) { + loaders = loaders.filter(l => !isESLintLoader(l)) + } else { + // This is a src import. Just make sure there's not more than 1 instance + // of eslint present. + loaders = dedupeESLintLoader(loaders) + } + } + + // remove self + loaders = loaders.filter(isPitcher) + + // do not inject if user uses null-loader to void the type (#1239) + if (loaders.some(isNullLoader)) { + return + } + + const genRequest = loaders => { + // Important: dedupe since both the original rule + // and the cloned rule would match a source import request. + // also make sure to dedupe based on loader path. + // assumes you'd probably never want to apply the same loader on the same + // file twice. + // Exception: in Vue CLI we do need two instances of postcss-loader + // for user config and inline minification. So we need to dedupe baesd on + // path AND query to be safe. + const seen = new Map() + const loaderStrings = [] + + loaders.forEach(loader => { + const identifier = typeof loader === 'string' + ? loader + : (loader.path + loader.query) + const request = typeof loader === 'string' ? loader : loader.request + if (!seen.has(identifier)) { + seen.set(identifier, true) + // loader.request contains both the resolved loader path and its options + // query (e.g. ??ref-0) + loaderStrings.push(request) + } + }) + + return loaderUtils.stringifyRequest(this, '-!' + [ + ...loaderStrings, + this.resourcePath + this.resourceQuery + ].join('!')) + } + + // Inject style-post-loader before css-loader for scoped CSS and trimming + if (query.type === `style`) { + const cssLoaderIndex = loaders.findIndex(isCSSLoader) + if (cssLoaderIndex > -1) { + const afterLoaders = loaders.slice(0, cssLoaderIndex + 1) + const beforeLoaders = loaders.slice(cssLoaderIndex + 1) + const request = genRequest([ + ...afterLoaders, + stylePostLoaderPath, + ...beforeLoaders + ]) + // console.log(request) + return `import mod from ${request}; export default mod; export * from ${request}` + } + } + + // for templates: inject the template compiler & optional cache + if (query.type === `template`) { + const path = require('path') + // fixed by xxxxxx + const cacheLoader = cacheDirectory && cacheIdentifier + ? [`${require.resolve('cache-loader')}??uni-cache-loader-template-options`] + : [] + + const preLoaders = loaders.filter(isPreLoader) + const postLoaders = loaders.filter(isPostLoader) + + const request = genRequest([ + ...cacheLoader, + ...postLoaders, + templateLoaderPath + `??vue-loader-options`, + ...preLoaders + ]) + // console.log(request) + // the template compiler uses esm exports + return `export * from ${request}` + } + + // if a custom block has no other matching loader other than vue-loader itself + // or cache-loader, we should ignore it + if (query.type === `custom` && shouldIgnoreCustomBlock(loaders)) { + return `` + } + + // When the user defines a rule that has only resourceQuery but no test, + // both that rule and the cloned rule will match, resulting in duplicated + // loaders. Therefore it is necessary to perform a dedupe here. + const request = genRequest(loaders) + return `import mod from ${request}; export default mod; export * from ${request}` +} diff --git a/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/template.recycle.js b/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/template.recycle.js index 579b1cfe47b88bd73b6a92d6c08c07f32044a554..6395854c0692da9e6a0ac14c558bc30639ba8a19 100644 --- a/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/template.recycle.js +++ b/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/template.recycle.js @@ -2,8 +2,8 @@ const loaderUtils = require('loader-utils') module.exports = function(content) { this.cacheable && this.cacheable() - const vueLoaderOptions = this.loaders.find(loader => loader.ident) - if (vueLoaderOptions && vueLoaderOptions && vueLoaderOptions.ident === 'vue-loader-options') { + const vueLoaderOptions = this.loaders.find(loader => loader.ident === 'vue-loader-options') + if (vueLoaderOptions) { const params = loaderUtils.parseQuery(this.resourceQuery) if (params.recyclable) { Object.assign(vueLoaderOptions.options.compilerOptions, { diff --git a/packages/vue-cli-plugin-uni/index.js b/packages/vue-cli-plugin-uni/index.js index b27f0efd191b0d75870648a67210aff3f1a22534..3e1a8cea95cbb5cdb87000a2d1a99102a7bb86b9 100644 --- a/packages/vue-cli-plugin-uni/index.js +++ b/packages/vue-cli-plugin-uni/index.js @@ -25,8 +25,8 @@ module.exports = (api, options) => { require('./lib/options')(options) - api.configureWebpack(require('./lib/configure-webpack')(platformOptions, manifestPlatformOptions, options)) - api.chainWebpack(require('./lib/chain-webpack')(platformOptions)) + api.configureWebpack(require('./lib/configure-webpack')(platformOptions, manifestPlatformOptions, options, api)) + api.chainWebpack(require('./lib/chain-webpack')(platformOptions, api)) } module.exports.defaultModes = { diff --git a/packages/vue-cli-plugin-uni/lib/cache-loader.js b/packages/vue-cli-plugin-uni/lib/cache-loader.js new file mode 100644 index 0000000000000000000000000000000000000000..a2ad4622a226ad9296baf58cf476827e4230d4d8 --- /dev/null +++ b/packages/vue-cli-plugin-uni/lib/cache-loader.js @@ -0,0 +1,82 @@ +const fs = require('fs') +const path = require('path') +const mkdirp = require('mkdirp') +const BJSON = require('buffer-json') + +const { + getPartialIdentifier +} = require('./util') + +const directories = new Set() + +function write (key, data, callback) { + const dirname = path.dirname(key) + // template,缓存 mp template + if ( + data.remainingRequest.indexOf('vue&type=template') !== -1 && + process.UNI_CACHE_TEMPLATES + ) { + data['mpTemplates'] = process.UNI_CACHE_TEMPLATES + delete process.UNI_CACHE_TEMPLATES + } + + const content = BJSON.stringify(data) + + if (directories.has(dirname)) { + // for performance skip creating directory + fs.writeFile(key, content, 'utf-8', callback) + } else { + mkdirp(dirname, (mkdirErr) => { + if (mkdirErr) { + callback(mkdirErr) + return + } + + directories.add(dirname) + + fs.writeFile(key, content, 'utf-8', callback) + }) + } +} + +function read (key, callback) { + fs.readFile(key, 'utf-8', (err, content) => { + if (err) { + callback(err) + return + } + + try { + const data = BJSON.parse(content) + const mpTemplates = data['mpTemplates'] + if (mpTemplates) { + Object.keys(mpTemplates).forEach(name => { + console.log('read=>write', name) + fs.writeFileSync(name, mpTemplates[name], 'utf-8') + }) + } + callback(null, data) + } catch (e) { + callback(e) + } + }) +} + +module.exports = { + createTemplateCacheLoader: function (api) { + return { + resourceQuery: /type=uni-cache-loader-template/, + use: [{ + loader: 'cache-loader', + ident: 'uni-cache-loader-template-options', + options: Object.assign(api.genCacheConfig( + 'uni-template-compiler/' + process.env.UNI_PLATFORM, + getPartialIdentifier() + ), { + read, + write + }) + }] + } + } +} diff --git a/packages/vue-cli-plugin-uni/lib/chain-webpack.js b/packages/vue-cli-plugin-uni/lib/chain-webpack.js index 5044e042b3e62bc1a849ab31e2468ab0a08e47a2..45dc249d4b97bfba714daf2fdaff1a0dbef5ac1e 100644 --- a/packages/vue-cli-plugin-uni/lib/chain-webpack.js +++ b/packages/vue-cli-plugin-uni/lib/chain-webpack.js @@ -4,11 +4,15 @@ const { sassLoaderVersion } = require('@dcloudio/uni-cli-shared/lib/scss') +const { + getPartialIdentifier +} = require('./util') + function resolve (dir) { return path.resolve(__dirname, '..', dir) } -module.exports = function chainWebpack (platformOptions) { +module.exports = function chainWebpack (platformOptions, api) { const { runByHBuilderX, // 使用 HBuilderX 运行 cssPreprocessOptions @@ -48,11 +52,22 @@ module.exports = function chainWebpack (platformOptions) { const langRule = webpackConfig.module.rule(lang) const loader = loaders[lang] cssTypes.forEach(type => { + if (process.env.UNI_USING_CACHE) { + langRule.oneOf(type) + .use(`uniapp-cache-css`) + .loader('cache-loader') + .options(api.genCacheConfig( + 'css-loader/' + process.env.UNI_PLATFORM, + getPartialIdentifier() + )) + .before('css-loader') + } langRule.oneOf(type) .use(`uniapp-preprocss`) .loader(resolve('packages/webpack-preprocess-loader')) .options(cssPreprocessOptions) .before('css-loader') // 在 css-loader 之后条件编译一次,避免 import 进来的 css 没有走条件编译 + if (loader) { // 在 scss,less,stylus 之前先条件编译一次 langRule.oneOf(type) .use(`uniapp-preprocss-` + lang) @@ -79,7 +94,7 @@ module.exports = function chainWebpack (platformOptions) { }) } - platformOptions.chainWebpack(webpackConfig) + platformOptions.chainWebpack(webpackConfig, api) // define webpackConfig .plugin('uni-define') diff --git a/packages/vue-cli-plugin-uni/lib/configure-webpack.js b/packages/vue-cli-plugin-uni/lib/configure-webpack.js index 5910640e7fdf2bf48e4e7433b8c1a58d669f5bc0..2873411eaadfbe3adff60cd6bd9a81ee3356cf17 100644 --- a/packages/vue-cli-plugin-uni/lib/configure-webpack.js +++ b/packages/vue-cli-plugin-uni/lib/configure-webpack.js @@ -6,6 +6,10 @@ const CopyWebpackPlugin = require('copy-webpack-plugin') const merge = require('webpack-merge') +const { + getPartialIdentifier +} = require('./util') + function resolve (dir) { return path.resolve(__dirname, '..', dir) } @@ -14,7 +18,7 @@ function resolveModule (dir) { return path.resolve(__dirname, '../../..', dir) } -module.exports = function configureWebpack (platformOptions, manifestPlatformOptions, vueOptions) { +module.exports = function configureWebpack (platformOptions, manifestPlatformOptions, vueOptions, api) { const { runByHBuilderX, // 使用 HBuilderX 运行 isInHBuilderX, // 在 HBuilderX 的插件中 @@ -138,13 +142,19 @@ module.exports = function configureWebpack (platformOptions, manifestPlatformOpt return function (webpackConfig) { // disable js cache-loader const rawRules = webpackConfig.module.rules - for (let i = rawRules.length - 1; i >= 0; i--) { const uses = rawRules[i].use if (Array.isArray(uses)) { if (uses.find(use => use.loader === 'babel-loader')) { const index = uses.findIndex(use => use.loader === 'cache-loader') - uses.splice(index, 1) + if (process.env.UNI_USING_CACHE) { + Object.assign(uses[index].options, api.genCacheConfig( + 'babel-loader/' + process.env.UNI_PLATFORM, + getPartialIdentifier() + )) + } else { + uses.splice(index, 1) + } } } } @@ -168,7 +178,7 @@ module.exports = function configureWebpack (platformOptions, manifestPlatformOpt let platformWebpackConfig = platformOptions.webpackConfig if (typeof platformWebpackConfig === 'function') { - platformWebpackConfig = platformWebpackConfig(webpackConfig) + platformWebpackConfig = platformWebpackConfig(webpackConfig, api) } // 移除 node_modules 目录,避免受路径上的 node_modules 影响 webpackConfig.resolve.modules = webpackConfig.resolve.modules.filter(module => module !== diff --git a/packages/vue-cli-plugin-uni/lib/env.js b/packages/vue-cli-plugin-uni/lib/env.js index 77228ceb17be47f63182bfb3ab7e060581a222c5..a7c1a5736f75ba2ae32b6e3d2bce86a3cb888c67 100644 --- a/packages/vue-cli-plugin-uni/lib/env.js +++ b/packages/vue-cli-plugin-uni/lib/env.js @@ -26,6 +26,10 @@ process.env.UNI_CLI_CONTEXT = path.resolve(__dirname, '../../../../') process.UNI_LIBRARIES = process.UNI_LIBRARIES || ['@dcloudio/uni-ui'] +if (process.env.NODE_ENV === 'production') { // 发行模式,不启用 cache + process.env.UNI_USING_CACHE = false +} + const { isSupportSubPackages, runByHBuilderX, @@ -254,8 +258,8 @@ if (runByHBuilderX) { } } -console.log(`正在编译中...`) +runByHBuilderX && console.log(`正在编译中...`) module.exports = { manifestPlatformOptions: platformOptions -} +} diff --git a/packages/vue-cli-plugin-uni/lib/h5/index.js b/packages/vue-cli-plugin-uni/lib/h5/index.js index 9f44dd8ab8d7472e37553cc81934b000c3fefd88..7a16c26b46f01190f78f175755a68a4aa83e66e7 100644 --- a/packages/vue-cli-plugin-uni/lib/h5/index.js +++ b/packages/vue-cli-plugin-uni/lib/h5/index.js @@ -4,10 +4,11 @@ const path = require('path') const { getMainEntry, getH5Options, - getPlatformCompiler, getPlatformCssnano } = require('@dcloudio/uni-cli-shared') +const modifyVueLoader = require('./vue-loader') + const WebpackHtmlAppendPlugin = require('../../packages/webpack-html-append-plugin') function resolve (dir) { @@ -100,7 +101,7 @@ module.exports = { plugins } }, - chainWebpack (webpackConfig) { + chainWebpack (webpackConfig, api) { webpackConfig.plugins.delete('copy') if (!process.env.UNI_OPT_PREFETCH) { @@ -109,29 +110,8 @@ module.exports = { if (!process.env.UNI_OPT_PRELOAD) { webpackConfig.plugins.delete('preload-index') } - // Vue - webpackConfig.module - .rule('vue') - .test([/\.vue$/, /\.nvue$/]) - .use('vue-loader') - .tap(options => Object.assign(options, { - compiler: getPlatformCompiler(), - compilerOptions: require('./compiler-options'), - cacheDirectory: false, - cacheIdentifier: false - })) - .end() - .use('uniapp-custom-block-loader') - .loader(require.resolve('@dcloudio/vue-cli-plugin-uni/packages/webpack-custom-block-loader')) - .options({ - compiler: getPlatformCompiler() - }) - .end() - .use('uniapp-scoped') - .loader(resolve('packages/webpack-scoped-loader')) - .end() - .uses - .delete('cache-loader') + + modifyVueLoader(webpackConfig, require('./compiler-options'), api) if (process.env.NODE_ENV === 'production') { const module = webpackConfig.module diff --git a/packages/vue-cli-plugin-uni/lib/mp.js b/packages/vue-cli-plugin-uni/lib/mp.js index ad8f49d9c00d04cc635c8947b4335db240e2dd2f..662519596835a1923d6cf15fb1a4b317810ded11 100644 --- a/packages/vue-cli-plugin-uni/lib/mp.js +++ b/packages/vue-cli-plugin-uni/lib/mp.js @@ -9,13 +9,14 @@ const { parseEntry, getMainEntry, getPlatformExts, - getPlatformCompiler, getPlatformCssnano } = require('@dcloudio/uni-cli-shared') +const modifyVueLoader = require('./vue-loader') + const { - isUnaryTag -} = require('./util') + createTemplateCacheLoader +} = require('./cache-loader') function createUniMPPlugin () { if (process.env.UNI_USING_COMPONENTS) { @@ -42,7 +43,7 @@ function getProvides () { process.env.UNI_PLATFORM === 'app-plus' && process.env.UNI_USING_V8 ) { - provides['__f__'] = [path.resolve(__dirname, 'format-log.js'), 'default'] + provides['__f__'] = [path.resolve(__dirname, 'format-log.js'), 'default'] provides['crypto'] = [path.resolve(__dirname, 'crypto.js'), 'default'] } @@ -61,7 +62,7 @@ module.exports = { vueConfig: { parallel: false }, - webpackConfig (webpackConfig) { + webpackConfig (webpackConfig, api) { if (!webpackConfig.optimization) { webpackConfig.optimization = {} } @@ -105,9 +106,9 @@ module.exports = { chunkFilename: '[id].js', globalObject: process.env.UNI_PLATFORM === 'mp-alipay' ? 'my' : 'global', sourceMapFilename: '../.sourcemap/' + process.env.UNI_PLATFORM + '/[name].js.map' - }, - performance: { - hints: false + }, + performance: { + hints: false }, resolve: { extensions: ['.nvue'], @@ -132,7 +133,7 @@ module.exports = { use: [{ loader: '@dcloudio/webpack-uni-mp-loader/lib/template' }] - }, { + }, createTemplateCacheLoader(api), { resourceQuery: [ /lang=wxs/, /lang=filter/, @@ -153,7 +154,7 @@ module.exports = { ] } }, - chainWebpack (webpackConfig) { + chainWebpack (webpackConfig, api) { if (process.env.UNI_PLATFORM === 'mp-baidu') { webpackConfig.module .rule('js') @@ -161,32 +162,9 @@ module.exports = { .add(/\.filter\.js$/) } - // disable vue cache-loader - webpackConfig.module - .rule('vue') - .test([/\.vue$/, /\.nvue$/]) - .use('vue-loader') - .tap(options => Object.assign(options, { - compiler: getPlatformCompiler(), - compilerOptions: process.env.UNI_USING_COMPONENTS ? { - isUnaryTag, - preserveWhitespace: false - } : require('./mp-compiler-options'), - cacheDirectory: false, - cacheIdentifier: false - })) - .end() - .use('uniapp-custom-block-loader') - .loader(require.resolve('@dcloudio/vue-cli-plugin-uni/packages/webpack-custom-block-loader')) - .options({ - compiler: getPlatformCompiler() - }) - .end() - .use('uniapp-nvue-loader') - .loader(require.resolve('@dcloudio/webpack-uni-mp-loader/lib/style.js')) - .end() - .uses - .delete('cache-loader') + const compilerOptions = process.env.UNI_USING_COMPONENTS ? {} : require('./mp-compiler-options') + + modifyVueLoader(webpackConfig, compilerOptions, api) const styleExt = getPlatformExts().style diff --git a/packages/vue-cli-plugin-uni/lib/util.js b/packages/vue-cli-plugin-uni/lib/util.js index f2b9be2ee2f261d31ae2812ed264534433a47fa6..b0112047379ac3a77c985830752cc69909616fc3 100644 --- a/packages/vue-cli-plugin-uni/lib/util.js +++ b/packages/vue-cli-plugin-uni/lib/util.js @@ -9,9 +9,24 @@ function makeMap (str, expectsLowerCase) { : val => map[val] } +let partialIdentifier = false module.exports = { isUnaryTag: makeMap( 'image,area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' + 'link,meta,param,source,track,wbr' - ) + ), + getPartialIdentifier () { + if (partialIdentifier) { + return partialIdentifier + } + partialIdentifier = { + 'UNI_COMPILER_VERSION': require('../package.json').version + } + Object.keys(process.env).forEach(name => { + if (name.indexOf('UNI_') === 0) { + partialIdentifier[name] = process.env[name] + } + }) + return partialIdentifier + } } diff --git a/packages/vue-cli-plugin-uni/lib/vue-loader.js b/packages/vue-cli-plugin-uni/lib/vue-loader.js new file mode 100644 index 0000000000000000000000000000000000000000..e680c62367b27e0b491b1276d2e19ccd350ebc6b --- /dev/null +++ b/packages/vue-cli-plugin-uni/lib/vue-loader.js @@ -0,0 +1,71 @@ +const { + getPlatformCompiler +} = require('@dcloudio/uni-cli-shared') + +const { + isUnaryTag, + getPartialIdentifier +} = require('./util') + +module.exports = function modifyVueLoader (webpackConfig, compilerOptions, api) { + // vue-loader options + + const cacheConfig = { + cacheDirectory: false, + cacheIdentifier: false + } + const partialIdentifier = {} + + if (process.env.UNI_USING_CACHE) { + Object.assign(cacheConfig, api.genCacheConfig( + 'vue-template-compiler/' + process.env.UNI_PLATFORM, + getPartialIdentifier() + )) + } + + webpackConfig.module + .rule('vue') + .test([/\.vue$/, /\.nvue$/]) + .use('vue-loader') + .tap(options => Object.assign(options, { + compiler: getPlatformCompiler(), + compilerOptions: Object.assign({ + isUnaryTag, + preserveWhitespace: false + }, compilerOptions) + }, cacheConfig)) + .end() + .use('uniapp-custom-block-loader') + .loader(require.resolve('@dcloudio/vue-cli-plugin-uni/packages/webpack-custom-block-loader')) + .options({ + compiler: getPlatformCompiler() + }) + + // h5 框架需要使用 scoped 样式,其他平台编译时识别是否 nvue 文件且注入 flex 相关样式 + if (process.env.UNI_PLATFORM === 'h5') { + webpackConfig.module + .rule('vue') + .use('uniapp-h5-style-scoped') + .loader(require.resolve('@dcloudio/vue-cli-plugin-uni/packages/webpack-scoped-loader')) + } else { + webpackConfig.module + .rule('vue') + .use('uniapp-nvue-style-loader') + .loader(require.resolve('@dcloudio/webpack-uni-mp-loader/lib/style.js')) + } + // 是否启用 cache + if (process.env.UNI_USING_CACHE) { + webpackConfig.module + .rule('vue') + .use('cache-loader') + .tap(options => Object.assign(options, api.genCacheConfig( + 'vue-loader/' + process.env.UNI_PLATFORM, + partialIdentifier + ))) + } else { + webpackConfig.module + .rule('vue') + .uses + .delete('cache-loader') + } +} diff --git a/packages/vue-cli-plugin-uni/package.json b/packages/vue-cli-plugin-uni/package.json index 84118991135cbfbf1635b4a31a302c2ce9eed4b3..34fe2e4c80d9ef4ae873d3dc637b0fc631a691f2 100644 --- a/packages/vue-cli-plugin-uni/package.json +++ b/packages/vue-cli-plugin-uni/package.json @@ -18,11 +18,13 @@ "license": "Apache-2.0", "dependencies": { "@dcloudio/uni-stat": "^2.0.0-23320190923002", + "buffer-json": "^2.0.0", "copy-webpack-plugin": "^4.6.0", "cross-env": "^5.2.0", "envinfo": "^6.0.1", "hash-sum": "^1.0.2", "loader-utils": "^1.1.0", + "mkdirp": "^0.5.1", "module-alias": "^2.1.0", "postcss": "^7.0.7", "postcss-import": "^12.0.1", diff --git a/packages/vue-cli-plugin-uni/packages/h5-vue-template-loader/index.js b/packages/vue-cli-plugin-uni/packages/h5-vue-template-loader/index.js index fcee3e6585837746cf4e2cc0d9bdb8e8eb347064..837dc1b8f5af47ba2cdfb650cb82b4886ee856c7 100644 --- a/packages/vue-cli-plugin-uni/packages/h5-vue-template-loader/index.js +++ b/packages/vue-cli-plugin-uni/packages/h5-vue-template-loader/index.js @@ -5,8 +5,8 @@ const loaderUtils = require('loader-utils') module.exports = function(content) { this.cacheable && this.cacheable() - const vueLoaderOptions = this.loaders.find(loader => loader.ident) - if (vueLoaderOptions && vueLoaderOptions.ident === 'vue-loader-options') { + const vueLoaderOptions = this.loaders.find(loader => loader.ident === 'vue-loader-options') + if (vueLoaderOptions) { const params = loaderUtils.parseQuery(this.resourceQuery) /* eslint-disable no-mixed-operators */ const filterModules = JSON.parse(params && params['filter-modules'] || '{}') diff --git a/packages/webpack-uni-mp-loader/lib/template-new.js b/packages/webpack-uni-mp-loader/lib/template-new.js index 492a30dc3c72d1de19cd498ab73d5c4e6143c9e4..9801d11f1ec9854d213c4a3f58b138c539a61b27 100644 --- a/packages/webpack-uni-mp-loader/lib/template-new.js +++ b/packages/webpack-uni-mp-loader/lib/template-new.js @@ -32,8 +32,8 @@ const filterTagName = getPlatformFilterTag() || '' module.exports = function (content) { this.cacheable && this.cacheable() - const vueLoaderOptions = this.loaders.find(loader => loader.ident) - if (vueLoaderOptions && vueLoaderOptions.ident === 'vue-loader-options') { + const vueLoaderOptions = this.loaders.find(loader => loader.ident === 'vue-loader-options') + if (vueLoaderOptions) { const globalUsingComponents = getGlobalUsingComponents() const realResourcePath = path.relative(process.env.UNI_INPUT_DIR, this.resourcePath) const resourcePath = normalizeNodeModules(removeExt(realResourcePath) + templateExt) diff --git a/packages/webpack-uni-mp-loader/lib/template.js b/packages/webpack-uni-mp-loader/lib/template.js index 5579d318c85a15057f5bb4d74e94024780aa1316..27556018f0478e4b429fde78ca157cbd567803e8 100644 --- a/packages/webpack-uni-mp-loader/lib/template.js +++ b/packages/webpack-uni-mp-loader/lib/template.js @@ -25,8 +25,8 @@ module.exports = function (content) { if (process.env.UNI_USING_COMPONENTS) { // 向 uni-template-compier 传递 emitFile - const vueLoaderOptions = this.loaders.find(loader => loader.ident) - if (vueLoaderOptions && vueLoaderOptions.ident === 'vue-loader-options') { + const vueLoaderOptions = this.loaders.find(loader => loader.ident === 'vue-loader-options') + if (vueLoaderOptions) { Object.assign(vueLoaderOptions.options.compilerOptions, { resourcePath: removeExt(realResourcePath) + templateExt, emitFile: this.emitFile @@ -57,8 +57,8 @@ module.exports = function (content) { cacheCompilerOptions(realResourcePath, compilerOptions) // 向 vue-loader templateLoader 传递 compilerOptions - const vueLoaderOptions = this.loaders.find(loader => loader.ident) - if (vueLoaderOptions && vueLoaderOptions.ident === 'vue-loader-options') { + const vueLoaderOptions = this.loaders.find(loader => loader.ident === 'vue-loader-options') + if (vueLoaderOptions) { Object.assign(vueLoaderOptions.options.compilerOptions, compilerOptions) } else { throw new Error('vue-loader-options parse error')