Skip to content

Commit

Permalink
fix(next): fix ts readDirectory, use fetch cache
Browse files Browse the repository at this point in the history
  • Loading branch information
adamdbradley committed Dec 23, 2019
1 parent 6fd43e7 commit 18360ca
Show file tree
Hide file tree
Showing 21 changed files with 418 additions and 176 deletions.
7 changes: 3 additions & 4 deletions src/cli_next/tasks/startup-log.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as d from '../../declarations';
import { compilerBuild } from '../../version';
import { buildId, vermoji, version } from '../../version';
import os from 'os';


Expand All @@ -10,7 +10,6 @@ export function startupLog(prcs: NodeJS.Process, config: d.Config) {

const logger = config.logger;
const isDebug = logger.level === 'debug';
const version = compilerBuild.stencilVersion;
const isPrerelease = version.includes('-');
const isDevBuild = version.includes('-dev.');

Expand All @@ -25,7 +24,7 @@ export function startupLog(prcs: NodeJS.Process, config: d.Config) {
startupMsg += ' ' + logger.magenta('[NEXT]');

if (prcs.platform !== 'win32') {
startupMsg += ' ' + compilerBuild.vermoji;
startupMsg += ' ' + vermoji;
}

logger.info(startupMsg);
Expand Down Expand Up @@ -61,7 +60,7 @@ export function startupLog(prcs: NodeJS.Process, config: d.Config) {

logger.debug(`node ${prcs.version}`);
logger.debug(`compiler: ${config.sys_next.getCompilerExecutingPath()}`);
logger.debug(`build: ${compilerBuild.buildId}`);
logger.debug(`build: ${buildId}`);

} catch (e) {
logger.warn(e);
Expand Down
6 changes: 6 additions & 0 deletions src/compiler_next/compiler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Cache } from '../compiler/cache';
import { cleanFetchCache } from './sys/fetch/fetch-cache';
import { CompilerNext, Config, Diagnostic } from '../declarations';
import { CompilerContext } from './build/compiler-ctx';
import { createFullBuild } from './build/full-build';
Expand All @@ -8,6 +9,7 @@ import { createWatchBuild } from './build/watch-build';
import { getConfig, patchSysLegacy } from './sys/config';
import { patchFs } from './sys/fs-patch';
import { patchTypescript } from './sys/typescript/typescript-patch';
import { preloadInMemoryFsFromCache } from './sys/fetch/fetch-preload';


export const createCompiler = async (config: Config) => {
Expand All @@ -28,6 +30,8 @@ export const createCompiler = async (config: Config) => {
compilerCtx.worker = createSysWorker(sys, config.maxConcurrentWorkers);
patchSysLegacy(config, compilerCtx);

await preloadInMemoryFsFromCache(config, compilerCtx.fs);

if (sys.events) {
// Pipe events from sys.events to compilerCtx
sys.events.on(compilerCtx.events.emit);
Expand All @@ -54,5 +58,7 @@ export const createCompiler = async (config: Config) => {

config.logger.printDiagnostics(diagnostics);

cleanFetchCache();

return compiler;
};
13 changes: 7 additions & 6 deletions src/compiler_next/config/load-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ const loadConfigFile = async (sys: CompilerSystem, diagnostics: Diagnostic[], co
if (hasConfigFile) {
// the passed in config was a string, so it's probably a path to the config we need to load
// first clear the require cache so we don't get the same file
const configFileData = evaluateConfigFile(sys, diagnostics, configPath);
const configFileData = await evaluateConfigFile(sys, diagnostics, configPath);
if (hasError(diagnostics)) {
return config;
}
Expand All @@ -152,11 +152,13 @@ const loadConfigFile = async (sys: CompilerSystem, diagnostics: Diagnostic[], co
const CONFIG_FILENAMES = ['stencil.config.ts', 'stencil.config.js'];


const evaluateConfigFile = (sys: CompilerSystem, diagnostics: Diagnostic[], configFilePath: string) => {
const evaluateConfigFile = async (sys: CompilerSystem, diagnostics: Diagnostic[], configFilePath: string) => {
let configFileData: { config?: Config } = null;

try {
// TODO: this should use sys for resolving
const ts = await loadTypescript(diagnostics);

if (IS_NODE_ENV) {
// ensure we cleared out node's internal require() cache for this file
delete require.cache[path.resolve(configFilePath)];
Expand All @@ -169,7 +171,7 @@ const evaluateConfigFile = (sys: CompilerSystem, diagnostics: Diagnostic[], conf
if (configFilePath.endsWith('.ts')) {
// looks like we've got a typed config file
// let's transpile it to .js quick
sourceText = transpileTypedConfig(diagnostics, sourceText, configFilePath);
sourceText = transpileTypedConfig(ts, diagnostics, sourceText, configFilePath);

} else {
// quick hack to turn a modern es module
Expand All @@ -189,7 +191,7 @@ const evaluateConfigFile = (sys: CompilerSystem, diagnostics: Diagnostic[], conf
} else {
// browser environment, can't use node's require() to evaluate
let sourceText = sys.readFileSync(configFilePath, 'utf8');
sourceText = transpileTypedConfig(diagnostics, sourceText, configFilePath);
sourceText = transpileTypedConfig(ts, diagnostics, sourceText, configFilePath);
if (hasError(diagnostics)) {
return configFileData;
}
Expand All @@ -206,10 +208,9 @@ const evaluateConfigFile = (sys: CompilerSystem, diagnostics: Diagnostic[], conf
};


const transpileTypedConfig = (diagnostics: Diagnostic[], sourceText: string, filePath: string) => {
const transpileTypedConfig = (ts: any, diagnostics: Diagnostic[], sourceText: string, filePath: string) => {
// let's transpile an awesome stencil.config.ts file into
// a boring stencil.config.js file
const ts = loadTypescript(diagnostics);
if (hasError(diagnostics)) {
return sourceText;
}
Expand Down
4 changes: 2 additions & 2 deletions src/compiler_next/optimize/optimize-module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CompilerCtx, Config, Diagnostic, SourceTarget } from '../../declarations';
import { compilerBuild } from '../../version';
import { minfyJsId } from '../../version';
import { transpileToEs5 } from '../transpile/transpile-to-es5';
import { minifyJs } from './minify-js';
import { DEFAULT_STYLE_MODE } from '@utils';
Expand All @@ -25,7 +25,7 @@ export async function optimizeModule(
};
}
const isDebug = (config.logLevel === 'debug');
const cacheKey = await compilerCtx.cache.createKey('optimizeModule', compilerBuild.minfyJsId, opts, isDebug);
const cacheKey = await compilerCtx.cache.createKey('optimizeModule', minfyJsId, opts, isDebug);
const cachedContent = await compilerCtx.cache.get(cacheKey);
if (cachedContent != null) {
return {
Expand Down
6 changes: 3 additions & 3 deletions src/compiler_next/sys/config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import * as d from '../../declarations';
import { cloneDocument, createDocument, serializeNodeToHtml } from '@mock-doc';
import { compilerBuild } from '../../version';
import { createLogger } from './logger';
import { createSystem } from './stencil-sys';
import { resolveModuleIdSync, resolvePackageJsonSync } from './resolve/resolve-module';
import { scopeCss } from '../../utils/shadow-css';
import { typescriptVersion, version } from '../../version';
import path from 'path';


Expand Down Expand Up @@ -40,8 +40,8 @@ export const patchSysLegacy = (config: d.Config, compilerCtx: d.CompilerCtx) =>
// old way
config.sys.compiler = {
name: '',
version: compilerBuild.stencilVersion,
typescriptVersion: compilerBuild.typescriptVersion,
version,
typescriptVersion,
packageDir: path.resolve(__dirname, '..')
},
config.sys.generateContentHash = config.sys_next.generateContentHash;
Expand Down
17 changes: 11 additions & 6 deletions src/compiler_next/sys/dependencies.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
import { compilerBuild } from '../../version';
import { rollupVersion, terserVersion, typescriptVersion } from '../../version';

const remoteDepUrl = 'https://cdn.jsdelivr.net/npm/';


export const getRemoteDependencyUrl = (dep: CompilerDependency) => {
return `${remoteDepUrl}${dep.name}${dep.version ? '@' + dep.version : ''}${dep.main}`;
export const getRemoteDependencyUrl = (dep: CompilerDependency) =>
`${remoteDepUrl}${dep.name}${dep.version ? '@' + dep.version : ''}${dep.main}`;


export const getRemoteTypeScriptUrl = () => {
const tsDep = dependencies.find(dep => dep.name === 'typescript');
return getRemoteDependencyUrl(tsDep);
};


export const dependencies: CompilerDependency[] = [
{
name: 'typescript',
version: compilerBuild.typescriptVersion,
version: typescriptVersion,
main: '/lib/typescript.js',
},
{
name: 'rollup',
version: compilerBuild.rollupVersion,
version: rollupVersion,
main: '/dist/rollup.browser.es.js'
},
{
name: 'terser',
version: compilerBuild.terserVersion,
version: terserVersion,
main: '/dist/bundle.min.js'
}
];
Expand Down
15 changes: 15 additions & 0 deletions src/compiler_next/sys/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,21 @@ export const IS_FETCH_ENV = (
typeof fetch === 'function'
);

export const HAS_FETCH_CACHE = (
IS_FETCH_ENV &&
typeof caches !== 'undefined' &&
typeof caches.match === 'function'
);

export const IS_WINDOWS_ENV = (
IS_NODE_ENV &&
global.process.platform === 'win32'
);

export const IS_CASE_SENSITIVE_FILE_NAMES = (
!IS_WINDOWS_ENV
);

export const requireFunc = (path: string) => (typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require)(path);

declare const __webpack_require__: (path: string) => any;
Expand Down
109 changes: 109 additions & 0 deletions src/compiler_next/sys/fetch/fetch-cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { HAS_FETCH_CACHE } from '../environment';
import { isString } from '@utils';
import { version } from '../../../version';


const activeFetches = new Map<string, Promise<Response>>();

export const cachedFetch = async (url: string) => {
const immutableCache = HAS_FETCH_CACHE ? await caches.open(CACHES.immutable) : null;
if (immutableCache) {
const cachedImmutableRsp = await immutableCache.match(url);
if (cachedImmutableRsp) {
return cachedImmutableRsp;
}
}

if (HAS_FETCH_CACHE && isCoreResource(url)) {
const coreCache = await caches.open(CACHES.core);
const cachedCoreRsp = await coreCache.match(url);
if (cachedCoreRsp) {
return cachedCoreRsp;
}
}

const activeFetch = activeFetches.get(url);
if (activeFetch) {
return activeFetch;
}

try {
const fetchPromise = fetch(url);
activeFetches.set(url, fetchPromise);

const fetchRsp = await fetchPromise;

if (HAS_FETCH_CACHE && fetchRsp.ok) {
if (isCoreResource(url)) {
const coreCache = await caches.open(CACHES.core);
coreCache.put(url, fetchRsp.clone());

} else if (isImmutableResponse(fetchRsp)) {
immutableCache.put(url, fetchRsp.clone());

} else if (HAS_FETCH_CACHE) {
const offlineCache = await caches.open(CACHES.offline);
offlineCache.put(url, fetchRsp.clone());
}
}

return fetchRsp;

} catch (e) {
if (HAS_FETCH_CACHE) {
const offlineReqCache = await caches.open(CACHES.offline);
const cachedOfflineRsp = await offlineReqCache.match(url);
if (cachedOfflineRsp) {
return cachedOfflineRsp;
}
}
}

return null;
};

export const isImmutableResponse = (rsp: Response) => {
if (rsp && rsp.ok && rsp.headers) {
const cacheControl = rsp.headers.get('Cache-Control');
if (isString(cacheControl)) {
if (cacheControl.includes('immutable')) {
return true;
}
}
}
return false;
};

export const cleanFetchCache = async () => {
if (HAS_FETCH_CACHE) {
try {
const currentCacheKeys = Object.values(CACHES);
const cacheKeys = await caches.keys();

const invalidCacheKeys = cacheKeys.filter(k => {
return !currentCacheKeys.includes(k);
});

await Promise.all(invalidCacheKeys.map(k => {
return caches.delete(k);
}));

} catch (e) {}
}
};

export const CACHES = {
core: `stencil_core_${version}`,
immutable: `stencil_immutable`,
offline: `stencil_offline`,
};


const isCoreResource = (url: string) => CORE_RESOURCES.some(u => url.includes(u));

const CORE_RESOURCES = [
'/@stencil/core/',
'/@stencil/core@',
'/typescript/',
'/typescript@',
];
49 changes: 20 additions & 29 deletions src/compiler_next/sys/fetch/fetch-module-async.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,31 @@
import * as d from '../../../declarations';
import { cachedFetch } from './fetch-cache';
import { known404Urls } from './fetch-utils';
import { skipFilePathFetch, skipUrlFetch } from '../fetch/fetch-utils';
import { writeFetchSuccess } from './write-fetch-success';
import { writeFetchSuccessAsync } from './write-fetch-success';


const fetchCacheAsync = new Map<string, Promise<string>>();


export const fetchModuleAsync = (inMemoryFs: d.InMemoryFileSystem, pkgVersions: Map<string, string>, url: string, filePath: string) => {
export const fetchModuleAsync = async (inMemoryFs: d.InMemoryFileSystem, pkgVersions: Map<string, string>, url: string, filePath: string) => {
if (skipFilePathFetch(filePath) || known404Urls.has(url) || skipUrlFetch(url)) {
return Promise.resolve(undefined);
return undefined;
}

let fetchPromise = fetchCacheAsync.get(url);

if (!fetchPromise) {
fetchPromise = new Promise(resolve => {
fetch(url)
.then(async rsp => {
if (rsp.status >= 200 && rsp.status < 300) {
const content = await rsp.text();
writeFetchSuccess(inMemoryFs, url, filePath, content, pkgVersions);
resolve(content);

} else {
known404Urls.add(url);
resolve(undefined);
}
})
.catch(() => {
known404Urls.add(url);
resolve(undefined);
});
});
fetchCacheAsync.set(url, fetchPromise);
try {
const rsp = await cachedFetch(url);
if (rsp) {
if (rsp.ok) {
const content = await rsp.clone().text();
writeFetchSuccessAsync(inMemoryFs, url, filePath, content, pkgVersions);
return content;
}

if (rsp.status === 404) {
known404Urls.add(url);
}
}
} catch (e) {
console.error(e);
}

return fetchPromise;
return undefined;
};
Loading

0 comments on commit 18360ca

Please sign in to comment.