diff --git a/packages/vant-cli/src/common/index.ts b/packages/vant-cli/src/common/index.ts index 1f1b15ad6..2276916e4 100644 --- a/packages/vant-cli/src/common/index.ts +++ b/packages/vant-cli/src/common/index.ts @@ -1,7 +1,13 @@ import decamelize from 'decamelize'; import { join } from 'path'; import { get } from 'lodash'; -import { readdirSync, existsSync, lstatSync, readFileSync } from 'fs-extra'; +import { + lstatSync, + existsSync, + readdirSync, + readFileSync, + outputFileSync +} from 'fs-extra'; import { CONFIG, SRC_DIR, WEBPACK_CONFIG_FILE } from './constant'; export const EXT_REGEXP = /\.\w+$/; @@ -114,4 +120,18 @@ export function getCssLang(): string { return preprocessor; } +// Smarter outputFileSync +// Skip if content unchanged +export function smartOutputFile(filePath: string, content: string) { + if (existsSync(filePath)) { + const previousContent = readFileSync(filePath, 'utf-8'); + + if (previousContent === content) { + return; + } + } + + outputFileSync(filePath, content); +} + export { decamelize }; diff --git a/packages/vant-cli/src/compiler/compile-js.ts b/packages/vant-cli/src/compiler/compile-js.ts index 4247a7bfd..c9685d1fd 100644 --- a/packages/vant-cli/src/compiler/compile-js.ts +++ b/packages/vant-cli/src/compiler/compile-js.ts @@ -1,14 +1,19 @@ -import { transformFileSync } from '@babel/core'; +import { transformFileAsync } from '@babel/core'; import { removeSync, outputFileSync } from 'fs-extra'; import { replaceExt } from '../common'; -export function compileJs(filePath: string) { - const result = transformFileSync(filePath); +export function compileJs(filePath: string): Promise { + return new Promise((resolve, reject) => { + transformFileAsync(filePath) + .then(result => { + if (result) { + const jsFilePath = replaceExt(filePath, '.js'); - if (result) { - const jsFilePath = replaceExt(filePath, '.js'); - - removeSync(filePath); - outputFileSync(jsFilePath, result.code); - } + removeSync(filePath); + outputFileSync(jsFilePath, result.code); + resolve(); + } + }) + .catch(reject); + }); } diff --git a/packages/vant-cli/src/compiler/compile-sfc.ts b/packages/vant-cli/src/compiler/compile-sfc.ts index 24efdaa96..5cd6cdba3 100644 --- a/packages/vant-cli/src/compiler/compile-sfc.ts +++ b/packages/vant-cli/src/compiler/compile-sfc.ts @@ -1,7 +1,7 @@ import * as compiler from 'vue-template-compiler'; import * as compileUtils from '@vue/component-compiler-utils'; import { parse } from 'path'; -import { removeSync, writeFileSync, readFileSync } from 'fs-extra'; +import { remove, writeFileSync, readFileSync } from 'fs-extra'; import { replaceExt } from '../common'; import { compileJs } from './compile-js'; import { compileStyle } from './compile-style'; @@ -63,7 +63,14 @@ function compileTemplate(template: string) { return result.code; } -export async function compileSfc(filePath: string) { +type CompileSfcOptions = { + skipStyle?: boolean; +}; + +export async function compileSfc( + filePath: string, + options: CompileSfcOptions = {} +): Promise { const source = readFileSync(filePath, 'utf-8'); const jsFilePath = replaceExt(filePath, '.js'); @@ -75,30 +82,44 @@ export async function compileSfc(filePath: string) { const { template, styles } = descriptor; - removeSync(filePath); + const tasks = [remove(filePath)]; // compile js part if (descriptor.script) { - let script = descriptor.script.content; - script = injectStyle(script, styles, filePath); + tasks.push( + new Promise((resolve, reject) => { + let script = descriptor.script!.content; + script = injectStyle(script, styles, filePath); - if (template) { - const render = compileTemplate(template.content); - script = injectRender(script, render); - } + if (template) { + const render = compileTemplate(template.content); + script = injectRender(script, render); + } - writeFileSync(jsFilePath, script); - compileJs(jsFilePath); + writeFileSync(jsFilePath, script); + compileJs(jsFilePath) + .then(resolve) + .catch(reject); + }) + ); } // compile style part - await Promise.all( - styles.map((style, index: number) => { - const cssFilePath = getSfcStylePath(filePath, style.lang || 'css', index); + if (!options.skipStyle) { + tasks.push( + ...styles.map((style, index: number) => { + const cssFilePath = getSfcStylePath( + filePath, + style.lang || 'css', + index + ); - writeFileSync(cssFilePath, trim(style.content)); + writeFileSync(cssFilePath, trim(style.content)); - return compileStyle(cssFilePath); - }) - ); + return compileStyle(cssFilePath); + }) + ); + } + + return Promise.all(tasks); } diff --git a/packages/vant-cli/src/compiler/compile-site.ts b/packages/vant-cli/src/compiler/compile-site.ts index 4da52247f..378b53f50 100644 --- a/packages/vant-cli/src/compiler/compile-site.ts +++ b/packages/vant-cli/src/compiler/compile-site.ts @@ -1,21 +1,13 @@ import webpack from 'webpack'; import WebpackDevServer from 'webpack-dev-server'; import { getPort } from 'portfinder'; -import { getStepper } from '../common/logger'; -import { genPackageEntry } from './gen-package-entry'; -import { genPacakgeStyle } from './gen-package-style'; -import { genSiteMobileShared } from './gen-site-mobile-shared'; -import { genSiteDesktopShared } from './gen-site-desktop-shared'; -import { genStyleDepsMap } from './gen-style-deps-map'; import { siteDevConfig } from '../config/webpack.site.dev'; import { sitePrdConfig } from '../config/webpack.site.prd'; -const stpper = getStepper(4); - function watch() { const server = new WebpackDevServer( webpack(siteDevConfig), - (siteDevConfig as any).devServer + siteDevConfig.devServer ); getPort( @@ -50,19 +42,9 @@ function build() { } export async function compileSite(production = false) { - stpper.start('Prepare For Compilation'); - await genStyleDepsMap(); - genPackageEntry(); - genPacakgeStyle(); - genSiteMobileShared(); - genSiteDesktopShared(); - stpper.success('Prepare For Compilation'); - - stpper.start('Build Documentation Site'); if (production) { await build(); } else { watch(); } - stpper.success('Build Documentation Site'); } diff --git a/packages/vant-cli/src/compiler/gen-package-entry.ts b/packages/vant-cli/src/compiler/gen-package-entry.ts index 5bfc89fcb..a796555cb 100644 --- a/packages/vant-cli/src/compiler/gen-package-entry.ts +++ b/packages/vant-cli/src/compiler/gen-package-entry.ts @@ -1,11 +1,6 @@ import { join } from 'path'; -import { writeFileSync } from 'fs-extra'; -import { pascalize, getComponents } from '../common'; -import { - SRC_DIR, - PACKAGE_JSON, - PACKAGE_ENTRY_FILE -} from '../common/constant'; +import { pascalize, getComponents, smartOutputFile } from '../common'; +import { SRC_DIR, PACKAGE_JSON, PACKAGE_ENTRY_FILE } from '../common/constant'; const version = process.env.PACKAGE_VERSION || PACKAGE_JSON.version; @@ -56,5 +51,5 @@ export default { }; `; - writeFileSync(PACKAGE_ENTRY_FILE, content); + smartOutputFile(PACKAGE_ENTRY_FILE, content); } diff --git a/packages/vant-cli/src/compiler/gen-package-style.ts b/packages/vant-cli/src/compiler/gen-package-style.ts index b38b1c115..b5b83e3cf 100644 --- a/packages/vant-cli/src/compiler/gen-package-style.ts +++ b/packages/vant-cli/src/compiler/gen-package-style.ts @@ -1,6 +1,5 @@ import { join } from 'path'; -import { writeFileSync } from 'fs-extra'; -import { replaceExt } from '../common'; +import { replaceExt, smartOutputFile } from '../common'; import { CSS_LANG, getCssBaseFile } from '../common/css'; import { SRC_DIR, @@ -23,5 +22,5 @@ export function genPacakgeStyle() { .map((name: string) => `@import "${join(SRC_DIR, `${name}/index${ext}`)}";`) .join('\n'); - writeFileSync(replaceExt(PACKAGE_STYLE_FILE, ext), content); + smartOutputFile(replaceExt(PACKAGE_STYLE_FILE, ext), content); } diff --git a/packages/vant-cli/src/compiler/gen-site-desktop-shared.ts b/packages/vant-cli/src/compiler/gen-site-desktop-shared.ts index f44611b22..4d9f0aa0e 100644 --- a/packages/vant-cli/src/compiler/gen-site-desktop-shared.ts +++ b/packages/vant-cli/src/compiler/gen-site-desktop-shared.ts @@ -1,7 +1,12 @@ import glob from 'fast-glob'; import { join, parse } from 'path'; -import { existsSync, writeFileSync } from 'fs-extra'; -import { pascalize, removeExt, getComponents } from '../common'; +import { existsSync } from 'fs-extra'; +import { + pascalize, + removeExt, + getComponents, + smartOutputFile +} from '../common'; import { SRC_DIR, DOCS_DIR, @@ -64,5 +69,5 @@ ${genExportConfig()} ${genExportDocuments(documents)} `; - writeFileSync(SITE_DESKTOP_SHARED_FILE, code); + smartOutputFile(SITE_DESKTOP_SHARED_FILE, code); } diff --git a/packages/vant-cli/src/compiler/gen-site-mobile-shared.ts b/packages/vant-cli/src/compiler/gen-site-mobile-shared.ts index eb8362e37..96b8ee0e1 100644 --- a/packages/vant-cli/src/compiler/gen-site-mobile-shared.ts +++ b/packages/vant-cli/src/compiler/gen-site-mobile-shared.ts @@ -1,10 +1,9 @@ import { join } from 'path'; -import { existsSync, ensureDirSync, writeFileSync } from 'fs-extra'; -import { decamelize, pascalize, removeExt, getComponents } from '../common'; +import { existsSync } from 'fs-extra'; +import { decamelize, pascalize, removeExt, getComponents, smartOutputFile } from '../common'; import { CONFIG, SRC_DIR, - DIST_DIR, SITE_MODILE_SHARED_FILE } from '../common/constant'; @@ -64,6 +63,5 @@ export function genSiteMobileShared() { const components = getComponents(); const code = genCode(components); - ensureDirSync(DIST_DIR); - writeFileSync(SITE_MODILE_SHARED_FILE, code); + smartOutputFile(SITE_MODILE_SHARED_FILE, code); } diff --git a/packages/vant-cli/src/compiler/gen-style-deps-map.ts b/packages/vant-cli/src/compiler/gen-style-deps-map.ts index ef6b3d3a0..69d796fd5 100644 --- a/packages/vant-cli/src/compiler/gen-style-deps-map.ts +++ b/packages/vant-cli/src/compiler/gen-style-deps-map.ts @@ -6,22 +6,16 @@ import dependencyTree from 'dependency-tree'; import { join } from 'path'; import { compileJs } from './compile-js'; import { compileSfc } from './compile-sfc'; -import { compileStyle } from './compile-style'; +import { CSS_LANG } from '../common/css'; +import { SRC_DIR, DIST_DIR, STYPE_DEPS_JSON_FILE } from '../common/constant'; +import { copySync, existsSync, readdirSync } from 'fs-extra'; import { isDir, isSfc, - isStyle, isScript, - getComponents + getComponents, + smartOutputFile } from '../common'; -import { SRC_DIR, DIST_DIR, STYPE_DEPS_JSON_FILE } from '../common/constant'; -import { - copy, - existsSync, - readdirSync, - writeFileSync, - ensureDirSync -} from 'fs-extra'; interface DependencyObj { [k: string]: DependencyObj; @@ -30,10 +24,10 @@ interface DependencyObj { const components = getComponents(); const TEMP_DIR = join(DIST_DIR, 'temp'); -async function compileTempDir(dir: string) { +function compileTempDir(dir: string): Promise { const files = readdirSync(dir); - await Promise.all( + return Promise.all( files.map(filename => { const filePath = join(dir, filename); @@ -43,16 +37,12 @@ async function compileTempDir(dir: string) { if (filename.indexOf('index') !== -1) { if (isSfc(filePath)) { - return compileSfc(filePath); + return compileSfc(filePath, { skipStyle: true }); } if (isScript(filePath)) { return compileJs(filePath); } - - if (isStyle(filePath)) { - return compileStyle(filePath); - } } return Promise.resolve(); @@ -81,7 +71,7 @@ function search(tree: DependencyObj, component: string, checkList: string[]) { } function getStylePath(component: string) { - return join(TEMP_DIR, `${component}/index.css`); + return join(TEMP_DIR, `${component}/index.${CSS_LANG}`); } function checkStyleExists(component: string) { @@ -147,27 +137,29 @@ function getSequence(depsMap: DepsMap) { } export async function genStyleDepsMap() { - const map = {} as DepsMap; + return new Promise(resolve => { + const map = {} as DepsMap; - await copy(SRC_DIR, TEMP_DIR); - await compileTempDir(TEMP_DIR); + copySync(SRC_DIR, TEMP_DIR); + compileTempDir(TEMP_DIR).then(() => { + components.filter(checkStyleExists).forEach(component => { + map[component] = analyzeDeps(component); + }); - components.filter(checkStyleExists).forEach(component => { - map[component] = analyzeDeps(component); + const sequence = getSequence(map); + + Object.keys(map).forEach(key => { + map[key] = map[key].sort( + (a, b) => sequence.indexOf(a) - sequence.indexOf(b) + ); + }); + + smartOutputFile( + STYPE_DEPS_JSON_FILE, + JSON.stringify({ map, sequence }, null, 2) + ); + + resolve(); + }); }); - - const sequence = getSequence(map); - - Object.keys(map).forEach(key => { - map[key] = map[key].sort( - (a, b) => sequence.indexOf(a) - sequence.indexOf(b) - ); - }); - - ensureDirSync(DIST_DIR); - - writeFileSync( - STYPE_DEPS_JSON_FILE, - JSON.stringify({ map, sequence }, null, 2) - ); } diff --git a/packages/vant-cli/src/compiler/vant-cli-site-plugin.ts b/packages/vant-cli/src/compiler/vant-cli-site-plugin.ts new file mode 100644 index 000000000..f97e34c69 --- /dev/null +++ b/packages/vant-cli/src/compiler/vant-cli-site-plugin.ts @@ -0,0 +1,28 @@ +import { Compiler } from 'webpack'; +import { genPackageEntry } from './gen-package-entry'; +import { genPacakgeStyle } from './gen-package-style'; +import { genSiteMobileShared } from './gen-site-mobile-shared'; +import { genSiteDesktopShared } from './gen-site-desktop-shared'; +import { genStyleDepsMap } from './gen-style-deps-map'; + +const PLUGIN_NAME = 'VantCliSitePlugin'; + +export class VantCliSitePlugin { + apply(compiler: Compiler) { + compiler.hooks.beforeCompile.tapPromise(PLUGIN_NAME, this.genSiteEntry); + } + + genSiteEntry() { + return new Promise((resolve, reject) => { + genStyleDepsMap() + .then(() => { + genPackageEntry(); + genPacakgeStyle(); + genSiteMobileShared(); + genSiteDesktopShared(); + resolve(); + }) + .catch(reject); + }); + } +} diff --git a/packages/vant-cli/src/config/webpack.site.dev.ts b/packages/vant-cli/src/config/webpack.site.dev.ts index 0aa19a1ef..1c86a39fa 100644 --- a/packages/vant-cli/src/config/webpack.site.dev.ts +++ b/packages/vant-cli/src/config/webpack.site.dev.ts @@ -3,6 +3,7 @@ import HtmlWebpackPlugin from 'html-webpack-plugin'; import { join } from 'path'; import { baseConfig } from './webpack.base'; import { getWebpackConfig } from '../common'; +import { VantCliSitePlugin } from '../compiler/vant-cli-site-plugin'; import { CONFIG, SITE_MODILE_SHARED_FILE, @@ -45,6 +46,7 @@ export const siteDevBaseConfig = merge(baseConfig as any, { } }, plugins: [ + new VantCliSitePlugin(), new HtmlWebpackPlugin({ title, logo: siteConfig.logo,