feat: platform suffix resolution [wip]

This commit is contained in:
Igor Randjelovic
2020-11-30 19:02:30 +01:00
parent ca78bc5ae8
commit 65b214b845
3 changed files with 182 additions and 1 deletions

View File

@ -18,6 +18,7 @@ import {
getPlatform,
} from '../helpers/project';
import { hasDependency } from '../helpers/dependencies';
import { PlatformSuffixPlugin } from '../plugins/PlatformSuffixPlugin';
export default function (config: Config, env: IWebpackEnv): Config {
const entryPath = getEntryPath();
@ -28,6 +29,10 @@ export default function (config: Config, env: IWebpackEnv): Config {
// set mode
config.mode(mode);
// config.stats({
// logging: 'verbose'
// })
// package.json is generated by the CLI with runtime options
// this ensures it's not included in the bundle, but rather
// resolved at runtime
@ -194,6 +199,22 @@ export default function (config: Config, env: IWebpackEnv): Config {
},
]);
// config.plugin('NormalModuleReplacementPlugin').use(NormalModuleReplacementPlugin, [
// /.*/,
// request => {
// if (new RegExp(`\.${platform}\..+$`).test(request.request)) {
// request.rawRequest = request.rawRequest.replace(`.${platform}.`, '.')
// console.log(request)
// }
// }
// ])
config.plugin('PlatformSuffixPlugin').use(PlatformSuffixPlugin, [
{
platform,
},
]);
// todo: refine defaults
config.plugin('DefinePlugin').use(DefinePlugin, [
{

View File

@ -1,4 +1,5 @@
import VirtualModulesPlugin from 'webpack-virtual-modules';
import { ContextExclusionPlugin } from 'webpack';
import Config from 'webpack-chain';
import dedent from 'ts-dedent';
import { join } from 'path';
@ -15,7 +16,12 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
config.entry('bundle').add(virtualEntryPath);
// Add a virtual entry module
config
.plugin('ContextExclusionPluginPlugin')
.use(ContextExclusionPlugin, [/__virtual_entry__\.js$/]);
// Add a virtual entry module that will register all modules into
// the nativescript module loader/handler
config.plugin('VirtualModulesPlugin').use(VirtualModulesPlugin, [
{
[virtualEntryPath]: dedent`
@ -26,6 +32,8 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
},
]);
config.resolve.extensions.add('.xml');
// set up xml
config.module
.rule('xml')

View File

@ -0,0 +1,152 @@
import { existsSync } from 'fs';
import { extname, resolve } from 'path';
const id = 'PlatformSuffixPlugin';
interface PlatformSuffixPluginOptions {
platform: string;
// extensions: string[] | (() => string[])
}
export class PlatformSuffixPlugin {
private readonly platform: string;
// private readonly extensions: string[]
constructor(options: PlatformSuffixPluginOptions) {
this.platform = options.platform;
// if (typeof options.extensions === "function") {
// this.extensions = options.extensions()
// } else {
// this.extensions = options.extensions
// }
}
apply(compiler: any) {
console.log(
// this.extensions,
this.platform
);
const platformRE = new RegExp(`\.${this.platform}\.`);
compiler.hooks.contextModuleFactory.tap(id, (cmf) => {
cmf.hooks.alternativeRequests.tap(id, (modules, options) => {
const additionalModules = [];
// we are looking for modules that are platform specific (something.<platform>.ext)
// and we are duplicating them without the platform suffix
// this allows using require.context with non-existent platformless filenames
// but mapped to the platform specific variant (done in the resolver hook below)
for (const module of modules) {
if (platformRE.test(module.request)) {
additionalModules.push({
...module,
request: module.request.replace(platformRE, '.'),
});
}
}
modules.push(...additionalModules);
});
});
compiler.resolverFactory.hooks.resolver
.for('normal')
.tap(id, (resolver) => {
// Object.keys(resolver.hooks).forEach(hook => {
// resolver.hooks[hook].tap(id, (request, resolveContext) => {
// if(
// request?.path?.includes('foo.xml') ||
// request?.request?.includes('foo.xml')
// ) {
// console.log(
// `>>> ${hook}: ${request.path}`,
// // request
// )
// }
// // callback();
// });
// })
resolver.hooks.normalResolve.tapAsync(
id,
(request_, resolveContext, callback) => {
const { path, request } = request_;
const ext = request && extname(request);
const platformExt = ext ? `.${this.platform}${ext}` : '';
if (path && request && ext && !request.includes(platformExt)) {
const platformRequest = request.replace(ext, platformExt);
const extPath = resolve(path, platformRequest);
// console.log({
// path,
// request,
// ext,
// extPath
// })
// if a file with the same + a platform suffix exists
// we want to resolve that file instead
if (existsSync(extPath)) {
const message = `resolving "${request}" to "${platformRequest}"`;
const hook = resolver.ensureHook('normalResolve');
console.log(message);
// here we are creating a new resolve object and replacing the path
// with the .<platform>.<ext> suffix
const obj = {
...request_,
path: resolver.join(path, platformRequest),
relativePath:
request_.relativePath &&
resolver.join(request_.relativePath, platformRequest),
request: undefined,
};
// we call to the actual resolver to do the resolving of this new file
return resolver.doResolve(
hook,
obj,
message,
resolveContext,
callback
);
}
}
callback();
}
);
// resolver.hooks.rawFile.tap(id, (request, resolveContext, callback) => {
// if(request.path && !/\.ios\..+$/.test(request.path)) {
// const { ext } = parse(request.path)
// const platformExtPath = request.path.replace(ext, `.${this.platform}${ext}`)
// // console.log({
// // p1: request.path,
// // p2: platformExtPath
// // })
// if(existsSync(platformExtPath)) {
// // request.path = platformExtPath
// // console.log('-'.repeat(100))
// // console.log(request)
// const obj = {
// ...request,
// path: platformExtPath,
// fullySpecified: false
// }
// return resolver.doResolve(
// 'raw-file',
// obj,
// `resolved ${request.path} to platform specific file: ${platformExtPath}`,
// resolveContext,
// (err, result) => {
// if(err) return callback(err);
// if(result) return callback(null, result);
// return callback();
// }
// )
// // return request
// }
// }
// });
});
}
}