@into-mini/sfc-split-plugin 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/helper/transform.mjs +32 -0
- package/dist/index.mjs +58 -0
- package/dist/loader/fake-vue-loader.mjs +118 -0
- package/dist/plugin/add-wxs.mjs +48 -0
- package/dist/plugin/entry-rename.mjs +78 -0
- package/dist/plugin/expose-entry-bk.mjs +63 -0
- package/dist/plugin/expose-entry.mjs +79 -0
- package/dist/plugin/mina-runtime.mjs +38 -0
- package/dist/plugin/sfc-split.mjs +74 -0
- package/package.json +8 -9
- package/helper/empty.json +0 -1
- package/helper/transform.mjs +0 -39
- package/loader/fake-vue-loader.mjs +0 -140
- package/plugin/add-wxs.mjs +0 -62
- package/plugin/entry-rename.mjs +0 -109
- package/plugin/expose-entry-bk.mjs +0 -86
- package/plugin/expose-entry.mjs +0 -104
- package/plugin/mina-runtime.mjs +0 -58
- package/plugin/sfc-split.mjs +0 -102
- package/plugin.mjs +0 -62
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// @ts-expect-error -------------------
|
|
2
|
+
import babel from '@babel/core';
|
|
3
|
+
export function transformJS(input, absoluteFrom) {
|
|
4
|
+
const minified = process.env.NODE_ENV === 'production';
|
|
5
|
+
if (!absoluteFrom.endsWith('.js') || absoluteFrom.endsWith('.mjs')) {
|
|
6
|
+
return input;
|
|
7
|
+
}
|
|
8
|
+
const result = babel.transformSync(input, {
|
|
9
|
+
presets: [
|
|
10
|
+
[
|
|
11
|
+
'babel-preset-evergreen',
|
|
12
|
+
{
|
|
13
|
+
usage: 'pure',
|
|
14
|
+
mini: true,
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
],
|
|
18
|
+
plugins: [
|
|
19
|
+
['@babel/plugin-transform-modules-commonjs', { importInterop: 'none' }],
|
|
20
|
+
],
|
|
21
|
+
targets: 'ios 12, chrome 86',
|
|
22
|
+
configFile: false,
|
|
23
|
+
babelrc: false,
|
|
24
|
+
filename: 'a.mjs',
|
|
25
|
+
sourceType: 'commonjs',
|
|
26
|
+
compact: !minified,
|
|
27
|
+
retainLines: !minified,
|
|
28
|
+
envName: process.env.NODE_ENV,
|
|
29
|
+
minified,
|
|
30
|
+
});
|
|
31
|
+
return (result?.code || input).replace(';Object.defineProperty(exports,"__esModule",{value:true});', ';');
|
|
32
|
+
}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
2
|
+
import { AddWxsPlugin } from "./plugin/add-wxs.mjs";
|
|
3
|
+
import { ExposeEntryNamePlugin } from "./plugin/expose-entry.mjs";
|
|
4
|
+
// import { EntryRenamePlugin } from './plugin/entry-rename.mjs';
|
|
5
|
+
import { SfcSplitPluginBase } from "./plugin/sfc-split.mjs";
|
|
6
|
+
import { MinaRuntimeWebpackPlugin } from "./plugin/mina-runtime.mjs";
|
|
7
|
+
export const COMPONENT_ROOT = 'as-components';
|
|
8
|
+
function reach(path) {
|
|
9
|
+
return fileURLToPath(import.meta.resolve(path));
|
|
10
|
+
}
|
|
11
|
+
export class SfcSplitPlugin {
|
|
12
|
+
options;
|
|
13
|
+
constructor({ type = false, tagMatcher, preserveTap } = {}) {
|
|
14
|
+
this.options = {
|
|
15
|
+
type,
|
|
16
|
+
tagMatcher,
|
|
17
|
+
preserveTap,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
#applyLoader(compiler) {
|
|
21
|
+
compiler.options.module.rules.push({
|
|
22
|
+
test: /\.vue$/,
|
|
23
|
+
use: [
|
|
24
|
+
{
|
|
25
|
+
loader: reach('./loader/fake-vue-loader.mts'),
|
|
26
|
+
options: {
|
|
27
|
+
componentRoot: COMPONENT_ROOT,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
loader: reach('@into-mini/sfc-split-loader/src/next.mts'),
|
|
32
|
+
options: this.options,
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
}, {
|
|
36
|
+
test: /\.wxml$/,
|
|
37
|
+
type: 'asset/resource',
|
|
38
|
+
loader: reach('@into-mini/wxml-loader'),
|
|
39
|
+
generator: {
|
|
40
|
+
filename: '[entry][ext]',
|
|
41
|
+
// filename: '[contenthash:8][ext]',
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
apply(compiler) {
|
|
46
|
+
this.#applyLoader(compiler);
|
|
47
|
+
const { type, tagMatcher, preserveTap } = this.options;
|
|
48
|
+
if (type) {
|
|
49
|
+
new AddWxsPlugin().apply(compiler);
|
|
50
|
+
new MinaRuntimeWebpackPlugin().apply(compiler);
|
|
51
|
+
new SfcSplitPluginBase({ tagMatcher, preserveTap }).apply(compiler);
|
|
52
|
+
new ExposeEntryNamePlugin().apply(compiler);
|
|
53
|
+
// new EntryRenamePlugin({ issuer: /\.vue$/, test: /\.wxml/ }).apply(
|
|
54
|
+
// compiler,
|
|
55
|
+
// );
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { join, relative, resolve } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { toJSONString } from '@into-mini/sfc-transformer/src/utils.mts';
|
|
7
|
+
import slash from 'slash';
|
|
8
|
+
function createShortHash(input) {
|
|
9
|
+
return createHash('sha256').update(input).digest('hex').slice(0, 8);
|
|
10
|
+
}
|
|
11
|
+
function reach(path) {
|
|
12
|
+
return fileURLToPath(import.meta.resolve(path));
|
|
13
|
+
}
|
|
14
|
+
function handleImport({ toThis, addSmartEntry, componentRoot, context, rootContext, maps, callback, }) {
|
|
15
|
+
if (Object.keys(maps).length > 0) {
|
|
16
|
+
for (const [name, path] of Object.entries(maps)) {
|
|
17
|
+
if (path.endsWith('.vue') && !path.startsWith('plugin://')) {
|
|
18
|
+
try {
|
|
19
|
+
const absolutePath = slash(path.startsWith('.') ? resolve(context, path) : reach(path));
|
|
20
|
+
const relativePath = slash(relative(rootContext, absolutePath));
|
|
21
|
+
const hack = relativePath.startsWith('..');
|
|
22
|
+
const entryName = hack
|
|
23
|
+
? [
|
|
24
|
+
componentRoot,
|
|
25
|
+
absolutePath
|
|
26
|
+
.split('/')
|
|
27
|
+
.slice(-2)
|
|
28
|
+
.join('/')
|
|
29
|
+
.replace(/\.vue$/, ''),
|
|
30
|
+
createShortHash(slash(relativePath)),
|
|
31
|
+
].join('/')
|
|
32
|
+
: relativePath.replace(/\.vue$/, '');
|
|
33
|
+
const placer = toThis(entryName);
|
|
34
|
+
callback({
|
|
35
|
+
name,
|
|
36
|
+
placer,
|
|
37
|
+
});
|
|
38
|
+
const entryPath = relativePath.startsWith('..')
|
|
39
|
+
? absolutePath
|
|
40
|
+
: `./${relativePath}`;
|
|
41
|
+
this.addDependency(resolve(absolutePath));
|
|
42
|
+
this.addMissingDependency(resolve(absolutePath));
|
|
43
|
+
addSmartEntry({
|
|
44
|
+
name: entryName,
|
|
45
|
+
path: entryPath,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
console.error(error);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export default function loader(source, map, meta) {
|
|
56
|
+
this.cacheable();
|
|
57
|
+
const callback = this.async();
|
|
58
|
+
const { componentRoot } = this.getOptions();
|
|
59
|
+
const { entryName: thisEntryName } = this;
|
|
60
|
+
const resourcePath = slash(this.resourcePath);
|
|
61
|
+
const { paths, config, script } = this.processSfcFile({
|
|
62
|
+
source,
|
|
63
|
+
resourcePath,
|
|
64
|
+
});
|
|
65
|
+
const { rootContext, context } = this;
|
|
66
|
+
for (const path of paths) {
|
|
67
|
+
const filePath = join(rootContext, path);
|
|
68
|
+
this.addDependency(filePath);
|
|
69
|
+
this.addMissingDependency(filePath);
|
|
70
|
+
}
|
|
71
|
+
function toThis(entryName) {
|
|
72
|
+
return slash(relative(`/${thisEntryName}/..`, `/${entryName}`));
|
|
73
|
+
}
|
|
74
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
75
|
+
const addSmartEntry = (io) => {
|
|
76
|
+
this.addSmartEntry(io);
|
|
77
|
+
};
|
|
78
|
+
if (config?.usingComponents) {
|
|
79
|
+
handleImport.bind(this)({
|
|
80
|
+
toThis,
|
|
81
|
+
addSmartEntry,
|
|
82
|
+
componentRoot,
|
|
83
|
+
context,
|
|
84
|
+
rootContext,
|
|
85
|
+
maps: config.usingComponents,
|
|
86
|
+
callback({ name, placer }) {
|
|
87
|
+
config.usingComponents[name] = placer;
|
|
88
|
+
if (placer.includes(componentRoot)) {
|
|
89
|
+
config.componentPlaceholder ??= {};
|
|
90
|
+
config.componentPlaceholder[name] = 'view';
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
if (config?.componentGenerics) {
|
|
96
|
+
handleImport.bind(this)({
|
|
97
|
+
toThis,
|
|
98
|
+
addSmartEntry,
|
|
99
|
+
componentRoot,
|
|
100
|
+
context,
|
|
101
|
+
rootContext,
|
|
102
|
+
maps: Object.fromEntries(Object.entries(config.componentGenerics)
|
|
103
|
+
.filter(([_, item]) => item?.default)
|
|
104
|
+
.map(([key, item]) => [key, item.default])),
|
|
105
|
+
callback({ name, placer }) {
|
|
106
|
+
config.componentGenerics[name].default = placer;
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
const file = [
|
|
111
|
+
...paths
|
|
112
|
+
.map((path) => relative(`${resourcePath}/..`, path))
|
|
113
|
+
.map((path) => `import "./${path}";`),
|
|
114
|
+
script,
|
|
115
|
+
].join('\n');
|
|
116
|
+
this.emitFile(`${thisEntryName}.json`, toJSONString(config));
|
|
117
|
+
callback(null, file, map, meta);
|
|
118
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { extname, join, relative } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { CLSX_PLACEHOLDER } from '@into-mini/sfc-transformer/src/utils.mts';
|
|
5
|
+
import slash from 'slash';
|
|
6
|
+
// WXS文件输出路径
|
|
7
|
+
const WXS_FILENAME = 'wxs/clsx.wxs';
|
|
8
|
+
/**
|
|
9
|
+
* 将clsx.wxs文件添加到编译结果中,并替换WXML文件中的占位符。
|
|
10
|
+
* 只在发现CLSX_PLACEHOLDER时添加wxs文件,且只添加一次。
|
|
11
|
+
*/
|
|
12
|
+
export class AddWxsPlugin {
|
|
13
|
+
PLUGIN_NAME = 'AddWxsPlugin';
|
|
14
|
+
apply(compiler) {
|
|
15
|
+
const { RawSource } = compiler.webpack.sources;
|
|
16
|
+
compiler.hooks.compilation.tap(this.PLUGIN_NAME, (compilation) => {
|
|
17
|
+
compilation.hooks.processAssets.tap({
|
|
18
|
+
name: this.PLUGIN_NAME,
|
|
19
|
+
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
|
|
20
|
+
}, (assets) => this.#processAssets(assets, compilation, RawSource));
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
#processAssets(assets, compilation, RawSource) {
|
|
24
|
+
// 处理所有wxml文件
|
|
25
|
+
for (const [filename, source] of Object.entries(assets)) {
|
|
26
|
+
if (extname(filename) === '.wxml') {
|
|
27
|
+
const content = source.source().toString();
|
|
28
|
+
if (content.includes(CLSX_PLACEHOLDER)) {
|
|
29
|
+
this.#addWxsFile(compilation, RawSource);
|
|
30
|
+
this.#replaceSource(compilation, RawSource, {
|
|
31
|
+
filename,
|
|
32
|
+
content,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
#replaceSource(compilation, RawSource, { filename, content }) {
|
|
39
|
+
const relativePath = slash(relative(join(filename, '..'), WXS_FILENAME));
|
|
40
|
+
const newContent = content.replace(CLSX_PLACEHOLDER, relativePath);
|
|
41
|
+
compilation.updateAsset(filename, new RawSource(newContent));
|
|
42
|
+
}
|
|
43
|
+
#addWxsFile(compilation, RawSource) {
|
|
44
|
+
const wxsPath = import.meta.resolve('@into-mini/clsx/index.wxs');
|
|
45
|
+
const wxsContent = readFileSync(fileURLToPath(wxsPath), 'utf8');
|
|
46
|
+
compilation.emitAsset(WXS_FILENAME, new RawSource(wxsContent));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/* eslint-disable no-continue */
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const pluginName = 'EntryRenamePlugin';
|
|
4
|
+
export class EntryRenamePlugin {
|
|
5
|
+
options;
|
|
6
|
+
constructor(options = {}) {
|
|
7
|
+
this.options = options;
|
|
8
|
+
}
|
|
9
|
+
getIssuerPath(issuerModule) {
|
|
10
|
+
return (issuerModule?.nameForCondition?.() ??
|
|
11
|
+
issuerModule?.resource ??
|
|
12
|
+
issuerModule?.identifier?.());
|
|
13
|
+
}
|
|
14
|
+
matchIssuer(issuerPath) {
|
|
15
|
+
const { issuer } = this.options;
|
|
16
|
+
if (!issuer) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
if (!issuerPath) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
if (issuer instanceof RegExp) {
|
|
23
|
+
return issuer.test(issuerPath);
|
|
24
|
+
}
|
|
25
|
+
if (typeof issuer === 'function') {
|
|
26
|
+
return issuer(issuerPath);
|
|
27
|
+
}
|
|
28
|
+
return issuerPath.includes(issuer);
|
|
29
|
+
}
|
|
30
|
+
matchTest(filename) {
|
|
31
|
+
const { test } = this.options;
|
|
32
|
+
if (!test) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
if (test instanceof RegExp) {
|
|
36
|
+
return test.test(filename);
|
|
37
|
+
}
|
|
38
|
+
if (typeof test === 'function') {
|
|
39
|
+
return test(filename);
|
|
40
|
+
}
|
|
41
|
+
return filename.includes(test);
|
|
42
|
+
}
|
|
43
|
+
apply(compiler) {
|
|
44
|
+
compiler.hooks.thisCompilation.tap(pluginName, (compilation) => {
|
|
45
|
+
const { Compilation } = compiler.webpack;
|
|
46
|
+
compilation.hooks.processAssets.tap({ name: pluginName, stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONS }, () => {
|
|
47
|
+
for (const module of compilation.modules) {
|
|
48
|
+
const filename = module.buildInfo?.filename;
|
|
49
|
+
if (!filename) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (!this.matchTest(filename)) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const issuerModule = compilation.moduleGraph.getIssuer(module);
|
|
56
|
+
const issuerPath = this.getIssuerPath(issuerModule);
|
|
57
|
+
if (!this.matchIssuer(issuerPath)) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const chunks = compilation.chunkGraph.getModuleChunks(module);
|
|
61
|
+
const entryChunk = [...chunks].find((chunk) => chunk.name);
|
|
62
|
+
if (!entryChunk?.name) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const ext = path.extname(filename);
|
|
66
|
+
const newName = `${entryChunk.name}${ext}`;
|
|
67
|
+
if (newName === filename) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (compilation.getAsset(newName)) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
compilation.renameAsset(filename, newName);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import slash from 'slash';
|
|
2
|
+
const PLUGIN_NAME = 'ExposeEntryNamePlugin';
|
|
3
|
+
export class ExposeEntryNamePlugin {
|
|
4
|
+
getEntryNameFromEntries(compilation, module) {
|
|
5
|
+
const { moduleGraph, entries } = compilation;
|
|
6
|
+
for (const [name, io] of entries) {
|
|
7
|
+
for (const dep of io.dependencies) {
|
|
8
|
+
const entryModule = moduleGraph.getModule(dep);
|
|
9
|
+
if (entryModule) {
|
|
10
|
+
if (
|
|
11
|
+
// @ts-expect-error ------------
|
|
12
|
+
entryModule.request && // @ts-expect-error ------------
|
|
13
|
+
slash(entryModule.request) === slash(module.request)) {
|
|
14
|
+
return name;
|
|
15
|
+
}
|
|
16
|
+
if (
|
|
17
|
+
// @ts-expect-error ------------
|
|
18
|
+
entryModule?.resource && // @ts-expect-error ------------
|
|
19
|
+
slash(entryModule?.resource) === slash(module.resource)) {
|
|
20
|
+
return name;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return '';
|
|
26
|
+
}
|
|
27
|
+
getEntryNameFromPathData(compilation, pathData) {
|
|
28
|
+
const mod = pathData.module;
|
|
29
|
+
const graph = pathData.chunkGraph;
|
|
30
|
+
if (mod && graph) {
|
|
31
|
+
const [entryModule] = graph
|
|
32
|
+
.getModuleChunks(mod)
|
|
33
|
+
.map((chunk) => [...graph.getChunkEntryModulesIterable(chunk)][0]);
|
|
34
|
+
if (entryModule) {
|
|
35
|
+
return this.getEntryNameFromEntries(compilation, entryModule);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return '';
|
|
39
|
+
}
|
|
40
|
+
apply(compiler) {
|
|
41
|
+
const { NormalModule: { getCompilationHooks }, } = compiler.webpack;
|
|
42
|
+
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
|
|
43
|
+
compilation.hooks.assetPath.tap(PLUGIN_NAME, (path, pathData) => {
|
|
44
|
+
if (path.includes('[entry]')) {
|
|
45
|
+
const entryName = this.getEntryNameFromPathData(compilation, pathData);
|
|
46
|
+
return entryName
|
|
47
|
+
? path.replaceAll('[entry]', entryName)
|
|
48
|
+
: path.replaceAll('[entry]', '[hash:8]');
|
|
49
|
+
}
|
|
50
|
+
return path;
|
|
51
|
+
});
|
|
52
|
+
getCompilationHooks(compilation).loader.tap(PLUGIN_NAME, (loaderContext, module) => {
|
|
53
|
+
Object.defineProperty(loaderContext, 'entryName', {
|
|
54
|
+
enumerable: true,
|
|
55
|
+
configurable: false,
|
|
56
|
+
get: () => {
|
|
57
|
+
return this.getEntryNameFromEntries(compilation, module);
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import slash from 'slash';
|
|
2
|
+
const PLUGIN_NAME = 'ExposeEntryNamePlugin';
|
|
3
|
+
export class ExposeEntryNamePlugin {
|
|
4
|
+
getEntryNameFromChunk(chunk) {
|
|
5
|
+
if (!chunk?.groupsIterable) {
|
|
6
|
+
return '';
|
|
7
|
+
}
|
|
8
|
+
for (const group of chunk.groupsIterable) {
|
|
9
|
+
if (group.isInitial()) {
|
|
10
|
+
return group.name;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return '';
|
|
14
|
+
}
|
|
15
|
+
getEntryNameFromEntries(compilation, module) {
|
|
16
|
+
const { moduleGraph, entries } = compilation;
|
|
17
|
+
for (const [name, io] of entries) {
|
|
18
|
+
for (const dep of io.dependencies) {
|
|
19
|
+
const entryModule = moduleGraph.getModule(dep);
|
|
20
|
+
if (entryModule) {
|
|
21
|
+
if (
|
|
22
|
+
// @ts-expect-error ------------
|
|
23
|
+
entryModule.request && // @ts-expect-error ------------
|
|
24
|
+
slash(entryModule.request) === slash(module.request)) {
|
|
25
|
+
return name;
|
|
26
|
+
}
|
|
27
|
+
if (
|
|
28
|
+
// @ts-expect-error ------------
|
|
29
|
+
entryModule?.resource && // @ts-expect-error ------------
|
|
30
|
+
slash(entryModule?.resource) === slash(module.resource)) {
|
|
31
|
+
return name;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return '';
|
|
37
|
+
}
|
|
38
|
+
getEntryNameFromPathData(pathData) {
|
|
39
|
+
if (pathData?.chunk) {
|
|
40
|
+
const entryName = this.getEntryNameFromChunk(pathData.chunk);
|
|
41
|
+
if (entryName) {
|
|
42
|
+
return entryName;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (pathData?.module && pathData?.chunkGraph) {
|
|
46
|
+
const chunks = pathData.chunkGraph.getModuleChunks(pathData.module);
|
|
47
|
+
for (const chunk of chunks) {
|
|
48
|
+
const entryName = this.getEntryNameFromChunk(chunk);
|
|
49
|
+
if (entryName) {
|
|
50
|
+
return entryName;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return '';
|
|
55
|
+
}
|
|
56
|
+
apply(compiler) {
|
|
57
|
+
const { NormalModule: { getCompilationHooks }, } = compiler.webpack;
|
|
58
|
+
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
|
|
59
|
+
compilation.hooks.assetPath.tap(PLUGIN_NAME, (path, pathData) => {
|
|
60
|
+
if (path.includes('[entry]')) {
|
|
61
|
+
const entryName = this.getEntryNameFromPathData(pathData);
|
|
62
|
+
return entryName
|
|
63
|
+
? path.replaceAll('[entry]', entryName)
|
|
64
|
+
: path.replaceAll('[entry]', '[hash:8]');
|
|
65
|
+
}
|
|
66
|
+
return path;
|
|
67
|
+
});
|
|
68
|
+
getCompilationHooks(compilation).loader.tap(PLUGIN_NAME, (loaderContext, module) => {
|
|
69
|
+
Object.defineProperty(loaderContext, 'entryName', {
|
|
70
|
+
enumerable: true,
|
|
71
|
+
configurable: false,
|
|
72
|
+
get: () => {
|
|
73
|
+
return this.getEntryNameFromEntries(compilation, module);
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { dirname, relative, sep } from 'node:path';
|
|
2
|
+
const PLUGIN_NAME = 'MinaRuntimeWebpackPlugin';
|
|
3
|
+
export class MinaRuntimeWebpackPlugin {
|
|
4
|
+
// 格式化依赖路径为require语句
|
|
5
|
+
#formatRequire = (from, to) => `require('./${relative(dirname(from), to).split(sep).join('/')}');\n`;
|
|
6
|
+
// 收集并生成所有依赖的require语句
|
|
7
|
+
#generateDependencies = (chunk) => {
|
|
8
|
+
if (!chunk?.name) {
|
|
9
|
+
return '';
|
|
10
|
+
}
|
|
11
|
+
let result = '';
|
|
12
|
+
for (const { chunks } of chunk.groupsIterable) {
|
|
13
|
+
for (const depChunk of chunks) {
|
|
14
|
+
if (depChunk !== chunk && depChunk.name) {
|
|
15
|
+
result += this.#formatRequire(chunk.name, depChunk.name);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
apply(compiler) {
|
|
22
|
+
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
|
|
23
|
+
const { javascript: { JavascriptModulesPlugin }, sources: { ConcatSource }, } = compiler.webpack;
|
|
24
|
+
JavascriptModulesPlugin.getCompilationHooks(compilation).renderChunk.tap(PLUGIN_NAME, (source, { chunk }) => {
|
|
25
|
+
if (!chunk ||
|
|
26
|
+
!compilation.chunkGraph.getNumberOfEntryModules(chunk)) {
|
|
27
|
+
// 跳过非入口模块
|
|
28
|
+
return source;
|
|
29
|
+
}
|
|
30
|
+
const deps = this.#generateDependencies(chunk);
|
|
31
|
+
if (!deps) {
|
|
32
|
+
return source;
|
|
33
|
+
}
|
|
34
|
+
return new ConcatSource(deps, source);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { parse } from '@into-mini/sfc-transformer/src/index.mjs';
|
|
5
|
+
import slash from 'slash';
|
|
6
|
+
import VirtualModulesPlugin from 'webpack-virtual-modules';
|
|
7
|
+
export class SfcSplitPluginBase extends VirtualModulesPlugin {
|
|
8
|
+
PLUGIN_NAME = 'SfcSplitPluginBase';
|
|
9
|
+
tagMatcher;
|
|
10
|
+
preserveTap;
|
|
11
|
+
constructor({ tagMatcher, preserveTap }) {
|
|
12
|
+
super();
|
|
13
|
+
this.tagMatcher = tagMatcher;
|
|
14
|
+
this.preserveTap = preserveTap;
|
|
15
|
+
}
|
|
16
|
+
apply(compiler) {
|
|
17
|
+
this.#expose(compiler);
|
|
18
|
+
super.apply(compiler);
|
|
19
|
+
}
|
|
20
|
+
#expose(compiler) {
|
|
21
|
+
const { PLUGIN_NAME } = this;
|
|
22
|
+
const { NormalModule: { getCompilationHooks }, } = compiler.webpack;
|
|
23
|
+
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
|
|
24
|
+
getCompilationHooks(compilation).loader.tap(PLUGIN_NAME, (loaderContext) => {
|
|
25
|
+
Object.defineProperty(loaderContext, 'processSfcFile', {
|
|
26
|
+
enumerable: true,
|
|
27
|
+
configurable: false,
|
|
28
|
+
value: (options) => {
|
|
29
|
+
return this.#processSfcFile(options);
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
#inject(resourcePath, ext, content) {
|
|
36
|
+
const src = path.resolve(resourcePath.replace(/\.vue$/, ext));
|
|
37
|
+
super.writeModule(src, content);
|
|
38
|
+
return src;
|
|
39
|
+
}
|
|
40
|
+
#injectStyle(resourcePath, id, style) {
|
|
41
|
+
return this.#inject(resourcePath, `-${id}.${style.lang ?? 'css'}`, style.content);
|
|
42
|
+
}
|
|
43
|
+
#injectStyles(resourcePath, styles) {
|
|
44
|
+
const io = [];
|
|
45
|
+
const css = styles?.length > 0 ? styles : [];
|
|
46
|
+
css.forEach((style, idx) => {
|
|
47
|
+
if (style?.content) {
|
|
48
|
+
const src = this.#injectStyle(resourcePath, idx, style);
|
|
49
|
+
io.push(src);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
return io;
|
|
53
|
+
}
|
|
54
|
+
#injectTemplate(resourcePath, tpl) {
|
|
55
|
+
return this.#inject(resourcePath, '.wxml', tpl);
|
|
56
|
+
}
|
|
57
|
+
#processSfcFile({ source, resourcePath }) {
|
|
58
|
+
const { tagMatcher, preserveTap } = this;
|
|
59
|
+
const { tpl, styles, code, config } = parse(source, {
|
|
60
|
+
tagMatcher,
|
|
61
|
+
preserveTap,
|
|
62
|
+
});
|
|
63
|
+
const paths = [];
|
|
64
|
+
const wxml = this.#injectTemplate(resourcePath, tpl);
|
|
65
|
+
paths.push(wxml);
|
|
66
|
+
const css = this.#injectStyles(resourcePath, styles);
|
|
67
|
+
paths.push(...css);
|
|
68
|
+
return {
|
|
69
|
+
config,
|
|
70
|
+
paths: paths.map((src) => slash(src)),
|
|
71
|
+
script: code,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@into-mini/sfc-split-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"loader",
|
|
@@ -22,10 +22,9 @@
|
|
|
22
22
|
"bugs": {
|
|
23
23
|
"url": "https://github.com/into-mini/into-mini/issues"
|
|
24
24
|
},
|
|
25
|
-
"main": "
|
|
25
|
+
"main": "dist/index.mjs",
|
|
26
26
|
"files": [
|
|
27
|
-
"
|
|
28
|
-
"**/*.mjs"
|
|
27
|
+
"dist"
|
|
29
28
|
],
|
|
30
29
|
"type": "module",
|
|
31
30
|
"dependencies": {
|
|
@@ -33,13 +32,12 @@
|
|
|
33
32
|
"webpack-virtual-modules": "^0.6.2",
|
|
34
33
|
"yaml": "^2.8.2",
|
|
35
34
|
"@into-mini/clsx": "^0.1.0",
|
|
36
|
-
"@into-mini/sfc-transformer": "^0.
|
|
37
|
-
"@into-mini/
|
|
38
|
-
"@into-mini/
|
|
35
|
+
"@into-mini/sfc-transformer": "^0.6.0",
|
|
36
|
+
"@into-mini/wxml-loader": "^0.0.0",
|
|
37
|
+
"@into-mini/sfc-split-loader": "^0.2.0"
|
|
39
38
|
},
|
|
40
39
|
"peerDependencies": {
|
|
41
40
|
"@babel/core": "^7.28.5",
|
|
42
|
-
"mini-css-extract-plugin": "^2.9.4",
|
|
43
41
|
"webpack": "^5.103.0"
|
|
44
42
|
},
|
|
45
43
|
"engines": {
|
|
@@ -48,5 +46,6 @@
|
|
|
48
46
|
"publishConfig": {
|
|
49
47
|
"access": "public",
|
|
50
48
|
"registry": "https://registry.npmjs.org/"
|
|
51
|
-
}
|
|
49
|
+
},
|
|
50
|
+
"scripts": {}
|
|
52
51
|
}
|
package/helper/empty.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{}
|
package/helper/transform.mjs
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
// @ts-expect-error -------------------
|
|
2
|
-
import babel from '@babel/core';
|
|
3
|
-
|
|
4
|
-
export function transformJS(input, absoluteFrom) {
|
|
5
|
-
const minified = process.env.NODE_ENV === 'production';
|
|
6
|
-
|
|
7
|
-
if (!absoluteFrom.endsWith('.js')) {
|
|
8
|
-
return input;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const result = babel.transformSync(input, {
|
|
12
|
-
presets: [
|
|
13
|
-
[
|
|
14
|
-
'babel-preset-evergreen',
|
|
15
|
-
{
|
|
16
|
-
usage: 'pure',
|
|
17
|
-
mini: true,
|
|
18
|
-
},
|
|
19
|
-
],
|
|
20
|
-
],
|
|
21
|
-
plugins: [
|
|
22
|
-
['@babel/plugin-transform-modules-commonjs', { importInterop: 'none' }],
|
|
23
|
-
],
|
|
24
|
-
targets: 'ios 12, chrome 86',
|
|
25
|
-
configFile: false,
|
|
26
|
-
babelrc: false,
|
|
27
|
-
filename: 'a.mjs',
|
|
28
|
-
sourceType: 'commonjs',
|
|
29
|
-
compact: !minified,
|
|
30
|
-
retainLines: !minified,
|
|
31
|
-
envName: process.env.NODE_ENV,
|
|
32
|
-
minified,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
return (result?.code || input).replace(
|
|
36
|
-
';Object.defineProperty(exports,"__esModule",{value:true});',
|
|
37
|
-
';',
|
|
38
|
-
);
|
|
39
|
-
}
|