-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
220 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
126 changes: 126 additions & 0 deletions
126
packages/taro-mini-runner/src/plugins/VirtualModulePlugin/VirtualModulePlugin.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import * as path from 'path' | ||
import VirtualStats from './virtualStats' | ||
|
||
export default class VirtualModulePlugin { | ||
options: { | ||
moduleName: string | ||
contents: any | ||
path?: string | ||
} | ||
constructor (options) { | ||
this.options = options | ||
} | ||
|
||
apply(compiler) { | ||
const moduleName = this.options.moduleName | ||
const ctime = VirtualModulePlugin.statsDate() | ||
let modulePath = this.options.path | ||
|
||
let contents | ||
if (typeof this.options.contents === 'string') { | ||
contents = this.options.contents | ||
} | ||
if (typeof this.options.contents === 'object') { | ||
if (typeof this.options.contents.then !== 'function') { | ||
contents = JSON.stringify(this.options.contents) | ||
} | ||
} | ||
if (typeof this.options.contents === 'function') { | ||
contents = this.options.contents() | ||
} | ||
if (typeof contents === 'string') { | ||
contents = Promise.resolve(contents) | ||
} | ||
|
||
function resolverPlugin(request, cb) { | ||
// populate the file system cache with the virtual module | ||
const fs = (this && this.fileSystem) || compiler.inputFileSystem | ||
const join = (this && this.join) || path.join | ||
|
||
if (typeof request === 'string') { | ||
request = cb | ||
cb = null | ||
} | ||
|
||
if (!modulePath) { | ||
modulePath = join(compiler.context, moduleName) | ||
} | ||
|
||
const resolve = (data) => { | ||
VirtualModulePlugin.populateFilesystem({ fs, modulePath, contents: data, ctime }) | ||
} | ||
|
||
const resolved = contents.then(resolve) | ||
if (!cb) { | ||
return | ||
} | ||
|
||
resolved.then(() => cb()) | ||
} | ||
|
||
compiler.hooks.normalModuleFactory.tap('VirtualModulePlugin', (nmf) => { | ||
nmf.hooks.beforeResolve.tap('VirtualModulePlugin', resolverPlugin) | ||
}) | ||
} | ||
|
||
static populateFilesystem(options) { | ||
const fs = options.fs | ||
const modulePath = options.modulePath | ||
const contents = options.contents | ||
const mapIsAvailable = typeof Map !== 'undefined' | ||
const statStorageIsMap = mapIsAvailable && fs._statStorage.data instanceof Map | ||
const readFileStorageIsMap = mapIsAvailable && fs._readFileStorage.data instanceof Map | ||
|
||
const stats = VirtualModulePlugin.createStats(options) | ||
if (statStorageIsMap) { // [email protected] or greater | ||
fs._statStorage.data.set(modulePath, [null, stats]) | ||
} else { // [email protected] or lower | ||
fs._statStorage.data[modulePath] = [null, stats] | ||
} | ||
if (readFileStorageIsMap) { // [email protected] or greater | ||
fs._readFileStorage.data.set(modulePath, [null, contents]) | ||
} else { // [email protected] or lower | ||
fs._readFileStorage.data[modulePath] = [null, contents] | ||
} | ||
} | ||
|
||
static statsDate (inputDate?) { | ||
if (!inputDate) { | ||
inputDate = new Date() | ||
} | ||
return inputDate.toString() | ||
} | ||
|
||
static createStats(options) { | ||
if (!options) { | ||
options = {} | ||
} | ||
if (!options.ctime) { | ||
options.ctime = VirtualModulePlugin.statsDate() | ||
} | ||
if (!options.mtime) { | ||
options.mtime = VirtualModulePlugin.statsDate() | ||
} | ||
if (!options.size) { | ||
options.size = 0 | ||
} | ||
if (!options.size && options.contents) { | ||
options.size = options.contents.length | ||
} | ||
return new VirtualStats({ | ||
dev: 8675309, | ||
nlink: 1, | ||
uid: 501, | ||
gid: 20, | ||
rdev: 0, | ||
blksize: 4096, | ||
ino: 44700000, | ||
mode: 33188, | ||
size: options.size, | ||
atime: options.mtime, | ||
mtime: options.mtime, | ||
ctime: options.ctime, | ||
birthtime: options.ctime, | ||
}) | ||
} | ||
} |
92 changes: 92 additions & 0 deletions
92
packages/taro-mini-runner/src/plugins/VirtualModulePlugin/virtualStats.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/** | ||
* Used to cache a stats object for the virtual file. | ||
* Extracted from the `mock-fs` package. | ||
* | ||
* @author Tim Schaub http://tschaub.net/ | ||
* @link https://github.com/tschaub/mock-fs/blob/master/lib/binding.js | ||
* @link https://github.com/tschaub/mock-fs/blob/master/license.md | ||
*/ | ||
|
||
import * as constants from 'constants' | ||
|
||
export default class VirtualStats { | ||
mode: number | ||
/** | ||
* Create a new stats object. | ||
* @param {Object} config Stats properties. | ||
* @constructor | ||
*/ | ||
constructor (config) { | ||
for (const key in config) { | ||
if (!config.hasOwnProperty(key)) { | ||
continue | ||
} | ||
this[key] = config[key] | ||
} | ||
} | ||
|
||
/** | ||
* Check if mode indicates property. | ||
* @param {number} property Property to check. | ||
* @return {boolean} Property matches mode. | ||
*/ | ||
_checkModeProperty(property) { | ||
return ((this.mode & constants.S_IFMT) === property) | ||
} | ||
|
||
|
||
/** | ||
* @return {Boolean} Is a directory. | ||
*/ | ||
isDirectory() { | ||
return this._checkModeProperty(constants.S_IFDIR) | ||
} | ||
|
||
|
||
/** | ||
* @return {Boolean} Is a regular file. | ||
*/ | ||
isFile() { | ||
return this._checkModeProperty(constants.S_IFREG) | ||
} | ||
|
||
|
||
/** | ||
* @return {Boolean} Is a block device. | ||
*/ | ||
isBlockDevice() { | ||
return this._checkModeProperty(constants.S_IFBLK) | ||
} | ||
|
||
|
||
/** | ||
* @return {Boolean} Is a character device. | ||
*/ | ||
isCharacterDevice() { | ||
return this._checkModeProperty(constants.S_IFCHR) | ||
} | ||
|
||
|
||
/** | ||
* @return {Boolean} Is a symbolic link. | ||
*/ | ||
isSymbolicLink() { | ||
return this._checkModeProperty(constants.S_IFLNK) | ||
} | ||
|
||
|
||
/** | ||
* @return {Boolean} Is a named pipe. | ||
*/ | ||
isFIFO() { | ||
return this._checkModeProperty(constants.S_IFIFO) | ||
} | ||
|
||
|
||
/** | ||
* @return {Boolean} Is a socket. | ||
*/ | ||
isSocket() { | ||
return this._checkModeProperty(constants.S_IFSOCK) | ||
} | ||
} |