Skip to content

Commit

Permalink
fixup and document cache attachment
Browse files Browse the repository at this point in the history
  • Loading branch information
guybedford committed Jun 25, 2019
1 parent fae8baa commit 0ca0374
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 24 deletions.
41 changes: 41 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,47 @@ Any `.node` files included will also support binary relocation.

Assets will be emitted using `emitAsset`, with their references updated in the code by the loader to the new output location.

### Asset Permissions and Symlinks

Asset symlinks and permissions are maintained in the loader, but aren't passed to Webpack as `emit` doesn't support these.

This information can be obtained from the loader through the API calls `getAssetPermissions()` and `getSymlinks()`:

```js
const relocateLoader = require('webpack-asset-relocator-loader');

webpack({...}).run((err, stats) => {
const assetPermissions = relocateLoader.getAssetPermissions();
const symlinks = relocateLoader.getSymlinks();
});
```

They will always contain the most recent build state.

### Caching

When using Webpack 5 caching, asset permissions need to be maintained through their own cache, and the public path needs to be injected into the build.

To ensure these cases work out, make sure to run `initAssetCache` in the build, with the `options.outputAssetBase` argument:

```js
const relocateLoader = require('webpack-asset-relocator-loader');

webpack({
// ...

plugins: [
{
apply(compiler) {
compiler.hooks.compilation.tap("ncc", compilation => {
relocateLoader.initAssetCache(compilation, outputAssetBase);
});
}
}
]
});
```

## How it Works

### Asset Relocation
Expand Down
52 changes: 28 additions & 24 deletions src/asset-relocator.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,7 @@ function getEntryIds (compilation) {
}
}

function assetBase (options) {
const outputAssetBase = options && options.outputAssetBase;
function assetBase (outputAssetBase) {
if (!outputAssetBase)
return '';
if (outputAssetBase.endsWith('/') || outputAssetBase.endsWith('\\'))
Expand Down Expand Up @@ -281,17 +280,8 @@ function generateWildcardRequire(dir, wildcardPath, wildcardParam, wildcardBlock
}

const hooked = new WeakSet();

module.exports = async function (content, map) {
if (this.cacheable)
this.cacheable();
this.async();
const id = this.resourcePath;
const dir = path.dirname(id);

// injection to set __webpack_require__.ab
const options = getOptions(this);
const { mainTemplate } = this._compilation;
function injectPathHook (compilation, outputAssetBase) {
const { mainTemplate } = compilation;
if (!hooked.has(mainTemplate)) {
hooked.add(mainTemplate);

Expand All @@ -302,22 +292,35 @@ module.exports = async function (content, map) {
if (relBase.length)
relBase = '/' + relBase;
}
return `${source}\n${mainTemplate.requireFn}.ab = __dirname + ${JSON.stringify(relBase + '/' + assetBase(options))};`;
return `${source}\n${mainTemplate.requireFn}.ab = __dirname + ${JSON.stringify(relBase + '/' + assetBase(outputAssetBase))};`;
});
}
}

module.exports = async function (content, map) {
if (this.cacheable)
this.cacheable();
this.async();
const id = this.resourcePath;
const dir = path.dirname(id);

// injection to set __webpack_require__.ab
const options = getOptions(this);

injectPathHook(this._compilation, options.outputAssetBase);

if (id.endsWith('.node')) {
const assetState = getAssetState(options, this._compilation);
const pkgBase = getPackageBase(this.resourcePath) || dir;
await sharedlibEmit(pkgBase, assetState, assetBase(options), this.emitFile);
await sharedlibEmit(pkgBase, assetState, assetBase(options.outputAssetBase), this.emitFile);

const name = getUniqueAssetName(id.substr(pkgBase.length + 1), id, assetState.assetNames);

const permissions = await new Promise((resolve, reject) =>
stat(id, (err, stats) => err ? reject(err) : resolve(stats.mode))
);
assetState.assetPermissions[name] = permissions;
this.emitFile(assetBase(options) + name, content);
this.emitFile(assetBase(options.outputAssetBase) + name, content);

this.callback(null, 'module.exports = __non_webpack_require__(__webpack_require__.ab + ' + JSON.stringify(name) + ')');
return;
Expand Down Expand Up @@ -354,7 +357,7 @@ module.exports = async function (content, map) {
outName = assetPath.substr(pkgBase.length).replace(/\\/g, '/');
// If the asset is a ".node" binary, then glob for possible shared
// libraries that should also be included
const nextPromise = sharedlibEmit(pkgBase, assetState, assetBase(options), this.emitFile);
const nextPromise = sharedlibEmit(pkgBase, assetState, assetBase(options.outputAssetBase), this.emitFile);
assetEmissionPromises = assetEmissionPromises.then(() => {
return nextPromise;
});
Expand All @@ -381,11 +384,11 @@ module.exports = async function (content, map) {
readlink(assetPath, (err, path) => err ? reject(err) : resolve(path));
});
const baseDir = path.dirname(assetPath);
assetState.assetSymlinks[assetBase(options) + name] = path.relative(baseDir, path.resolve(baseDir, symlink));
assetState.assetSymlinks[assetBase(options.outputAssetBase) + name] = path.relative(baseDir, path.resolve(baseDir, symlink));
}
else {
assetState.assetPermissions[assetBase(options) + name] = stats.mode;
this.emitFile(assetBase(options) + name, source);
assetState.assetPermissions[assetBase(options.outputAssetBase) + name] = stats.mode;
this.emitFile(assetBase(options.outputAssetBase) + name, source);
}
});
return "__webpack_require__.ab + " + JSON.stringify(name);
Expand Down Expand Up @@ -429,11 +432,11 @@ module.exports = async function (content, map) {
readlink(file, (err, path) => err ? reject(err) : resolve(path));
});
const baseDir = path.dirname(file);
assetState.assetSymlinks[assetBase(options) + name + file.substr(assetDirPath.length)] = path.relative(baseDir, path.resolve(baseDir, symlink)).replace(/\\/g, '/');
assetState.assetSymlinks[assetBase(options.outputAssetBase) + name + file.substr(assetDirPath.length)] = path.relative(baseDir, path.resolve(baseDir, symlink)).replace(/\\/g, '/');
}
else {
assetState.assetPermissions[assetBase(options) + name + file.substr(assetDirPath.length)] = stats.mode;
this.emitFile(assetBase(options) + name + file.substr(assetDirPath.length), source);
assetState.assetPermissions[assetBase(options.outputAssetBase) + name + file.substr(assetDirPath.length)] = stats.mode;
this.emitFile(assetBase(options.outputAssetBase) + name + file.substr(assetDirPath.length), source);
}
}));
});
Expand Down Expand Up @@ -1214,7 +1217,8 @@ module.exports.getSymlinks = function() {
return lastState.assetSymlinks;
};

module.exports.initAssetPermissionsCache = function (compilation) {
module.exports.initAssetCache = module.exports.initAssetPermissionsCache = function (compilation, outputAssetBase) {
injectPathHook(compilation, outputAssetBase);
const entryIds = getEntryIds(compilation);
if (!entryIds)
return;
Expand Down

0 comments on commit 0ca0374

Please sign in to comment.