@playcraft/devkit 1.0.31-beta.10 → 1.0.31-beta.11
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/README.md +262 -0
- package/cli/bin/playable-scripts.js +53 -6
- package/cli/commands/build.js +241 -32
- package/cli/commands/builds.js +13 -2
- package/cli/commands/dev.js +22 -1
- package/cli/commands/pack.js +320 -40
- package/cli/commands/vite-dev.js +7 -1
- package/core/artifacts/emit.js +98 -1
- package/core/artifacts/fflate.js +31 -1
- package/core/artifacts/zip.js +39 -1
- package/core/batch-build.js +1261 -147
- package/core/constants.js +20 -2
- package/core/cos-uploader.js +289 -23
- package/core/engines/cocos/clean-cache.js +179 -5
- package/core/engines/cocos/clean-cache.test.js +75 -1
- package/core/engines/cocos/cli-build.js +116 -2
- package/core/engines/cocos/cli.js +38 -1
- package/core/engines/cocos/constants.js +21 -1
- package/core/engines/cocos/creator-cli.js +108 -1
- package/core/engines/cocos/dev-server.js +412 -4
- package/core/engines/cocos/fs.js +105 -1
- package/core/engines/cocos/injects/3x/init.js +438 -19
- package/core/engines/cocos/injects/3x/main.js +52 -2
- package/core/engines/cocos/injects/libs/pako.js +2 -1
- package/core/engines/cocos/mcp-refresh.js +76 -2
- package/core/engines/cocos/merge.js +147 -2
- package/core/engines/cocos/pack.js +187 -1
- package/core/engines/cocos/preview-cache.js +48 -2
- package/core/engines/cocos/preview-cache.test.js +32 -1
- package/core/engines/cocos/preview-concat.js +189 -5
- package/core/engines/cocos/preview-concat.test.js +73 -1
- package/core/engines/cocos/preview-json-hook.js +200 -1
- package/core/engines/cocos/preview-json-pack.js +376 -2
- package/core/engines/cocos/preview-json-pack.test.js +226 -2
- package/core/engines/cocos/preview-proxy.js +132 -1
- package/core/engines/cocos/rebundle-preview.js +54 -2
- package/core/engines/cocos/strip-social-share.js +115 -3
- package/core/engines/cocos/theme-assets.js +161 -2
- package/core/engines/cocos/writable-cli.js +248 -2
- package/core/engines/cocos/writable-cli.test.js +112 -1
- package/core/engines/web/index.js +20 -1
- package/core/engines/web/vite.dev.js +322 -17
- package/core/engines/web/webpack.build.js +522 -65
- package/core/engines/web/webpack.common.js +177 -11
- package/core/engines/web/webpack.dev.js +88 -6
- package/core/index.js +101 -7
- package/core/injectors/apply.js +94 -1
- package/core/injectors/check-channel-matrix.js +130 -2
- package/core/injectors/spec.js +217 -9
- package/core/loaders/gltf-loader.js +74 -28
- package/core/options.js +353 -16
- package/core/plugins/AdikteevInjectorPlugin.js +26 -4
- package/core/plugins/BigoAdsInjectorPlugin.js +21 -4
- package/core/plugins/DAPIInjectorPlugin.js +25 -2
- package/core/plugins/DebuggerInjectionPlugin.js +31 -3
- package/core/plugins/ExitAPIInjectorPlugin.js +56 -3
- package/core/plugins/FflateCompressionPlugin.js +231 -40
- package/core/plugins/FontInjectionWebpackPlugin.js +46 -4
- package/core/plugins/LiftoffInjectorPlugin.js +26 -4
- package/core/plugins/MRAIDInjectorPlugin.js +24 -2
- package/core/plugins/MintegralInjectorPlugin.js +25 -2
- package/core/plugins/PangleInjectorPlugin.js +24 -2
- package/core/plugins/PlaycraftOrientationInjectorPlugin.js +29 -3
- package/core/plugins/SnapchatInjectorPlugin.js +26 -4
- package/core/plugins/SocialMediaInjectorPlugin.js +119 -7
- package/core/plugins/TikTokInjectorPlugin.js +24 -2
- package/core/plugins/UnityInjectorPlugin.js +37 -8
- package/core/plugins/ZipPlugin.js +154 -20
- package/core/plugins/socialMediaVitePlugin.js +108 -2
- package/core/utils/buildDefines.js +30 -2
- package/core/utils/buildTemplateString.js +39 -5
- package/core/utils/date.js +16 -1
- package/core/utils/fontRegistry.js +81 -13
- package/core/utils/fontResolver.js +335 -37
- package/core/utils/generateAdikteevHtmlWebpackPluginConfig.js +42 -7
- package/core/utils/generateBigabidHtmlWebpackPluginConfig.js +30 -3
- package/core/utils/generateInMobiHtmlWebpackPluginConfig.js +43 -7
- package/core/utils/getPlaycraftOrientationSuffix.js +9 -2
- package/core/utils/injectSDKPlugins.js +68 -13
- package/core/utils/logOptions.js +46 -5
- package/core/utils/mergeOptions.js +21 -2
- package/core/utils/parseArgvOptions.js +125 -5
- package/core/utils/resolveChannelFold2Zip.js +15 -3
- package/core/utils/validateThemeData.js +227 -26
- package/core/validators/pre-build-checker.js +287 -25
- package/core/validators/tracking-validator.js +441 -40
- package/core/validators/tracking-validator.test.js +84 -2
- package/core/vite.dev.js +1 -1
- package/core/webpack.build.js +1 -1
- package/core/webpack.common.js +1 -1
- package/core/webpack.dev.js +1 -1
- package/package.json +3 -2
package/core/injectors/spec.js
CHANGED
|
@@ -1,10 +1,34 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const { buildDefines } = require('../utils/buildDefines');
|
|
5
|
+
|
|
6
|
+
const META = {
|
|
7
|
+
COMMON_CHARSET: 'utf-8',
|
|
8
|
+
COMMON_VIEWPORT: 'width=device-width,initial-scale=1.0,viewport-fit=cover,maximum-scale=1.0,user-scalable=no',
|
|
9
|
+
MINTEGRAL_VIEWPORT: 'width=device-width,user-scalable=no,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const LIFTOFF_FONT = '<style>body{font-family:Roboto,"Helvetica Neue",-apple-system,BlinkMacSystemFont,sans-serif}</style>';
|
|
13
|
+
|
|
14
|
+
const zipOutputNetworks = [
|
|
15
|
+
'google', 'pangle', 'tiktok', 'vungle', 'mytarget', 'mintegral', 'adikteev',
|
|
16
|
+
'bigabid', 'inmobi', 'snapchat', 'bigoads', 'liftoff', 'facebook', 'remerge'
|
|
17
|
+
];
|
|
18
|
+
const zipOutputAllowedNetworks = ['moloco'];
|
|
19
|
+
|
|
20
|
+
/** Only platforms that require a separate JS file on CDN. Facebook / mintegral zip = single inlined index.html. */
|
|
21
|
+
const splitJsNetworks = ['adikteev', 'bigabid'];
|
|
22
|
+
|
|
23
|
+
const ADIKTEEV_INDEX = `<meta charset="UTF-8">
|
|
2
24
|
<link rel="stylesheet" href="style.css">
|
|
3
25
|
<script type="application/javascript">
|
|
4
26
|
var AK_CLICK_DESTINATION_URL = "PLACEHOLDER_CLICK_REDIRECT";
|
|
5
27
|
var AK_CLICK_PIXEL_URL = "PLACEHOLDER_CLICK_PIXEL";
|
|
6
28
|
</script>
|
|
7
|
-
<script type="application/javascript" src="creative.js"></script>`;
|
|
29
|
+
<script type="application/javascript" src="creative.js"></script>`;
|
|
30
|
+
|
|
31
|
+
const BIGABID_INDEX = `<meta charset="UTF-8">
|
|
8
32
|
<script src="mraid.js"></script>
|
|
9
33
|
<script>window.BIGABID_BIDTIMEMACROS = {
|
|
10
34
|
mraid_viewable: unescape("#IMP_TRACE_MRAID_VIEWABLE_ESC#"),
|
|
@@ -15,7 +39,45 @@
|
|
|
15
39
|
final_url: unescape("#FINAL_LANDING_URL_ESC#")
|
|
16
40
|
}</script>
|
|
17
41
|
<script src="#BIGABID_PLAYABLE_CDN_URL#"></script>
|
|
18
|
-
%{IMP_BEACON}`;
|
|
42
|
+
%{IMP_BEACON}`;
|
|
43
|
+
|
|
44
|
+
const dapiSrc =
|
|
45
|
+
'function getScript(e,i){var n=document.createElement("script");n.type="text/javascript",n.async=!0,i&&(n.onload=i),n.src=e,document.head.appendChild(n)}function parseMessage(e){var i=e.data,n=i.indexOf(DOLLAR_PREFIX+RECEIVE_MSG_PREFIX);if(-1!==n){var t=i.slice(n+2);return getMessageParams(t)}return{}}function getMessageParams(e){var i,n=[],t=e.split("/"),a=t.length;if(-1===e.indexOf(RECEIVE_MSG_PREFIX)){if(a>=2&&a%2===0)for(i=0;a>i;i+=2)n[t[i]]=t.length<i+1?null:decodeURIComponent(t[i+1])}else{var o=e.split(RECEIVE_MSG_PREFIX);void 0!==o[1]&&(n=JSON&&JSON.parse(o[1]))}return n}function getDapi(e){var i=parseMessage(e);if(!i||i.name===GET_DAPI_URL_MSG_NAME){var n=i.data;getScript(n,onDapiReceived)}}function invokeDapiListeners(){for(var e in dapiEventsPool)dapiEventsPool.hasOwnProperty(e)&&dapi.addEventListener(e,dapiEventsPool[e])}function onDapiReceived(){dapi=window.dapi,window.removeEventListener("message",getDapi),invokeDapiListeners()}function init(){window.dapi.isDemoDapi&&(window.parent.postMessage(DOLLAR_PREFIX+SEND_MSG_PREFIX+JSON.stringify({state:"getDapiUrl"}),"*"),window.addEventListener("message",getDapi,!1))}var DOLLAR_PREFIX="$$",RECEIVE_MSG_PREFIX="DAPI_SERVICE:",SEND_MSG_PREFIX="DAPI_AD:",GET_DAPI_URL_MSG_NAME="connection.getDapiUrl",dapiEventsPool={},dapi=window.dapi||{isReady:function(){return!1},addEventListener:function(e,i){dapiEventsPool[e]=i},removeEventListener:function(e){delete dapiEventsPool[e]},isDemoDapi:!0};init();';
|
|
46
|
+
|
|
47
|
+
const mintegralSrc =
|
|
48
|
+
'function gameStart() {window.mintGameStart && window.mintGameStart()}; function gameClose() {window.mintGameClose && window.mintGameClose()}';
|
|
49
|
+
|
|
50
|
+
const RESOURCES = path.join(__dirname, '../resources');
|
|
51
|
+
|
|
52
|
+
function scriptSrc(src) {
|
|
53
|
+
return { tagName: 'script', attributes: { src, type: 'text/javascript' } };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function scriptInline(innerHTML) {
|
|
57
|
+
return { tagName: 'script', attributes: { type: 'text/javascript' }, innerHTML };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function metaTag(attrs) {
|
|
61
|
+
return { tagName: 'meta', attributes: attrs };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function buildWindowScript(buildOptions, themePayload) {
|
|
65
|
+
const defines = buildDefines(buildOptions);
|
|
66
|
+
const lines = Object.entries(defines).map(([key, value]) => `window.${key}=${value};`);
|
|
67
|
+
const orientation = JSON.stringify(buildOptions.playcraftOrientationValue || 'both');
|
|
68
|
+
lines.push(`window.playcraftOrientation=${orientation};`);
|
|
69
|
+
if (themePayload) {
|
|
70
|
+
lines.push(`window.__PLAYCRAFT_THEME_DATA__=${JSON.stringify(themePayload.mergedData || {})};`);
|
|
71
|
+
lines.push(`window.__PLAYCRAFT_THEME_I18N_OVERRIDE__=${JSON.stringify(themePayload.i18nOverride || {})};`);
|
|
72
|
+
lines.push(`window.__PLAYCRAFT_THEME_ASSETS__=${JSON.stringify(themePayload.assetRecordByPath || {})};`);
|
|
73
|
+
}
|
|
74
|
+
return lines.join('');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function buildChannelScanStubHtml(buildOptions = {}) {
|
|
78
|
+
const googlePlayUrl = buildOptions.googlePlayUrl || 'https://play.google.com/store/games';
|
|
79
|
+
const appStoreUrl = buildOptions.appStoreUrl || 'https://www.apple.com/app-store/';
|
|
80
|
+
return `
|
|
19
81
|
<script>
|
|
20
82
|
(function() {
|
|
21
83
|
// 为了通过渠道的检测,伪造几个对象和方法 FbPlayableAd.onCTAClick(); ExitApi.exit();window.BGY_MRAID.open() mraid.open(destinationUrl); dapi.openStoreUrl(); NUC.trigger.convert(destinationUrl)
|
|
@@ -67,7 +129,10 @@
|
|
|
67
129
|
: ${JSON.stringify(googlePlayUrl)};
|
|
68
130
|
mraid.open(destinationUrl);
|
|
69
131
|
}
|
|
70
|
-
</script
|
|
132
|
+
</script>`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const SNAPCHAT_MOCK = `
|
|
71
136
|
// Snapchat Playable Ad SDK Mock (开发环境)
|
|
72
137
|
if (typeof ScPlayableAd === 'undefined') {
|
|
73
138
|
window.ScPlayableAd = {
|
|
@@ -80,14 +145,47 @@ if (typeof ScPlayableAd === 'undefined') {
|
|
|
80
145
|
};
|
|
81
146
|
console.log('[Snapchat] SDK initialized (development mode)');
|
|
82
147
|
}
|
|
83
|
-
`.trim();
|
|
148
|
+
`.trim();
|
|
149
|
+
|
|
150
|
+
function hasScriptSrc(headTags, src) {
|
|
151
|
+
return headTags.some((tag) => tag.tagName === 'script' && tag.attributes && tag.attributes.src === src);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function buildShareMetaHtml(shareMeta) {
|
|
155
|
+
if (!shareMeta) return '';
|
|
156
|
+
const esc = (s) => String(s)
|
|
157
|
+
.replace(/&/g, '&')
|
|
158
|
+
.replace(/"/g, '"')
|
|
159
|
+
.replace(/</g, '<')
|
|
160
|
+
.replace(/>/g, '>');
|
|
161
|
+
const title = (shareMeta.title || '').trim();
|
|
162
|
+
const description = (shareMeta.description || '').trim();
|
|
163
|
+
const image = (shareMeta.imageUrl || '').trim();
|
|
164
|
+
const url = (shareMeta.pageUrl || '').trim();
|
|
165
|
+
const siteName = (shareMeta.siteName || '').trim();
|
|
166
|
+
const lines = [];
|
|
167
|
+
if (title) lines.push(`<meta property="og:title" content="${esc(title)}" />`);
|
|
168
|
+
if (description) lines.push(`<meta property="og:description" content="${esc(description)}" />`);
|
|
169
|
+
if (image) lines.push(`<meta property="og:image" content="${esc(image)}" />`);
|
|
170
|
+
if (url) lines.push(`<meta property="og:url" content="${esc(url)}" />`);
|
|
171
|
+
if (siteName) lines.push(`<meta property="og:site_name" content="${esc(siteName)}" />`);
|
|
172
|
+
lines.push('<meta property="og:type" content="website" />');
|
|
173
|
+
lines.push('<meta name="twitter:card" content="summary_large_image" />');
|
|
174
|
+
if (title) lines.push(`<meta name="twitter:title" content="${esc(title)}" />`);
|
|
175
|
+
if (description) lines.push(`<meta name="twitter:description" content="${esc(description)}" />`);
|
|
176
|
+
if (image) lines.push(`<meta name="twitter:image" content="${esc(image)}" />`);
|
|
177
|
+
return lines.join('\n ');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function buildInmobiScript(buildOptions) {
|
|
181
|
+
return `<script>
|
|
84
182
|
var INMOBI_DSPMACROS = {
|
|
85
183
|
"Ad_Load_Start": ["$P_AD_LOAD_START"],
|
|
86
184
|
"Ad_Viewable": ["$P_AD_READY"],
|
|
87
185
|
"First_Engagement": ["$P_FIRST_ENGAGEMENT"],
|
|
88
186
|
"Gameplay_Complete": ["$P_GAMEPLAY_DONE"],
|
|
89
187
|
"DSP_Click": ["$HTML_ESC_CLICK_URL"],
|
|
90
|
-
"LandingPage_URL": [/android/i.test(navigator.userAgent) ? ${JSON.stringify(buildOptions.googlePlayUrl||
|
|
188
|
+
"LandingPage_URL": [/android/i.test(navigator.userAgent) ? ${JSON.stringify(buildOptions.googlePlayUrl || '')} : ${JSON.stringify(buildOptions.appStoreUrl || '')}],
|
|
91
189
|
"Spent_5_Seconds": ["$P_TIMESPENT_5"],
|
|
92
190
|
"Spent_10_Seconds": ["$P_TIMESPENT_10"],
|
|
93
191
|
"Spent_15_Seconds": ["$P_TIMESPENT_15"],
|
|
@@ -96,12 +194,122 @@ if (typeof ScPlayableAd === 'undefined') {
|
|
|
96
194
|
"Spent_30_Seconds": ["$P_TIMESPENT_30"]
|
|
97
195
|
};
|
|
98
196
|
</script>
|
|
99
|
-
<script src="mraid.js"></script
|
|
197
|
+
<script src="mraid.js"></script>`;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
100
201
|
* Mirror injectSDKPlugins.js + webpack.build.js extra files / meta.
|
|
101
202
|
* Webpack plugins stay untouched; Cocos apply.js consumes this spec.
|
|
102
|
-
*/
|
|
203
|
+
*/
|
|
204
|
+
function getChannelInjectionSpec(buildOptions, themePayload) {
|
|
205
|
+
const network = buildOptions.network;
|
|
206
|
+
const protocol = buildOptions.protocol;
|
|
207
|
+
const orientation = buildOptions.playcraftOrientationValue || 'both';
|
|
208
|
+
const headTags = [];
|
|
209
|
+
const htmlTransforms = [];
|
|
210
|
+
const extraFiles = [];
|
|
211
|
+
|
|
212
|
+
headTags.push(scriptInline(buildWindowScript(buildOptions, themePayload)));
|
|
213
|
+
|
|
214
|
+
if (protocol === 'dapi') {
|
|
215
|
+
headTags.push(scriptInline(dapiSrc));
|
|
216
|
+
} else if (protocol === 'mraid' && (network === 'ironsource' || network === 'remerge')) {
|
|
217
|
+
headTags.push(scriptSrc('mraid.js'));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (network === 'google') {
|
|
221
|
+
const width = orientation === 'landscape' ? 480 : 320;
|
|
222
|
+
const height = orientation === 'landscape' ? 320 : 480;
|
|
223
|
+
headTags.push(metaTag({ name: 'ad.orientation', content: orientation === 'both' ? 'portrait,landscape' : orientation }));
|
|
224
|
+
headTags.push(metaTag({ name: 'ad.size', content: `width=${width},height=${height}` }));
|
|
225
|
+
headTags.push(scriptSrc('https://tpc.googlesyndication.com/pagead/gadgets/html5/api/exitapi.js'));
|
|
226
|
+
} else if (network === 'unity') {
|
|
227
|
+
if (!hasScriptSrc(headTags, 'mraid.js')) headTags.push(scriptSrc('mraid.js'));
|
|
228
|
+
htmlTransforms.push((html) => html.replace(/window\.top\b/g, 'window'));
|
|
229
|
+
} else if (network === 'pangle') {
|
|
230
|
+
headTags.push(scriptSrc('https://sf3-ttcdn-tos.pstatp.com/obj/union-fe-nc/playable/sdk/playable-sdk.js'));
|
|
231
|
+
} else if (network === 'tiktok') {
|
|
232
|
+
headTags.push(scriptSrc('https://sf16-muse-va.ibytedtos.com/obj/union-fe-nc-i18n/playable/sdk/playable-sdk.js'));
|
|
233
|
+
} else if (network === 'mintegral') {
|
|
234
|
+
headTags.push(scriptInline(mintegralSrc));
|
|
235
|
+
} else if (network === 'bigoads') {
|
|
236
|
+
headTags.push(scriptSrc('https://static-web.likeevideo.com/as/common-static/big-data/dsp-public/bgy-mraid-sdk.js'));
|
|
237
|
+
} else if (network === 'liftoff') {
|
|
238
|
+
if (!hasScriptSrc(headTags, 'mraid.js')) headTags.push(scriptSrc('mraid.js'));
|
|
239
|
+
} else if (network === 'snapchat') {
|
|
240
|
+
headTags.push(scriptInline(SNAPCHAT_MOCK));
|
|
241
|
+
} else if (network === 'inmobi') {
|
|
242
|
+
htmlTransforms.push((html) => html.replace(/<\/head>/i, `${buildInmobiScript(buildOptions)}\n</head>`));
|
|
243
|
+
} else if (network === 'social_media') {
|
|
244
|
+
const shareMeta = themePayload && themePayload.mergedData && themePayload.mergedData.gamePlay
|
|
245
|
+
? themePayload.mergedData.gamePlay.shareMeta
|
|
246
|
+
: null;
|
|
247
|
+
const tags = buildShareMetaHtml(shareMeta);
|
|
248
|
+
if (tags) {
|
|
249
|
+
htmlTransforms.push((html) => html.replace(/<\/head>/i, ` ${tags}\n </head>`));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (network === 'tiktok') {
|
|
254
|
+
extraFiles.push({ from: path.join(RESOURCES, 'tiktok-config.json'), to: 'config.json' });
|
|
255
|
+
} else if (network === 'snapchat') {
|
|
256
|
+
extraFiles.push({ from: path.join(RESOURCES, 'snapchat-config.json'), to: 'config.json' });
|
|
257
|
+
} else if (network === 'bigoads') {
|
|
258
|
+
extraFiles.push({ from: path.join(RESOURCES, 'bigoads-config.json'), to: 'config.json' });
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
network,
|
|
263
|
+
headTags,
|
|
264
|
+
htmlTransforms,
|
|
265
|
+
extraFiles,
|
|
266
|
+
viewport: network === 'mintegral' ? META.MINTEGRAL_VIEWPORT : META.COMMON_VIEWPORT,
|
|
267
|
+
skipRecommendedMeta: !!buildOptions.skipRecommendedMeta,
|
|
268
|
+
liftoffFont: network === 'liftoff',
|
|
269
|
+
scanStubHtml: buildChannelScanStubHtml(buildOptions),
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
103
274
|
* Pack layout for one channel. Zip vs html follows webpack.build.js zipOutputNetworks.
|
|
104
275
|
* Zip internals: webpack skips HtmlInlineScriptPlugin for mintegral/facebook/adikteev/bigabid.
|
|
105
276
|
* Cocos already merged to one HTML, so facebook/mintegral stay inlined single index.html;
|
|
106
277
|
* only adikteev / bigabid keep a separate JS file (CDN).
|
|
107
|
-
*/
|
|
278
|
+
*/
|
|
279
|
+
function getChannelPackPlan(buildOptions, themePayload) {
|
|
280
|
+
const spec = getChannelInjectionSpec(buildOptions, themePayload);
|
|
281
|
+
const network = buildOptions.network;
|
|
282
|
+
const isZip = zipOutputNetworks.includes(network)
|
|
283
|
+
|| !!(buildOptions.zip && zipOutputAllowedNetworks.includes(network));
|
|
284
|
+
let layout = 'inline-html';
|
|
285
|
+
if (network === 'adikteev') layout = 'adikteev';
|
|
286
|
+
else if (network === 'bigabid') layout = 'bigabid';
|
|
287
|
+
return {
|
|
288
|
+
network,
|
|
289
|
+
isZip,
|
|
290
|
+
layout,
|
|
291
|
+
spec,
|
|
292
|
+
extraFiles: spec.extraFiles,
|
|
293
|
+
zipEntries: layout === 'adikteev'
|
|
294
|
+
? ['index.html', 'creative.js', 'style.css']
|
|
295
|
+
: layout === 'bigabid'
|
|
296
|
+
? ['index.html', 'main.js']
|
|
297
|
+
: isZip
|
|
298
|
+
? ['index.html', ...spec.extraFiles.map((f) => f.to)]
|
|
299
|
+
: [`${buildOptions.filename || 'playable'}.html`],
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
module.exports = {
|
|
304
|
+
META,
|
|
305
|
+
LIFTOFF_FONT,
|
|
306
|
+
zipOutputNetworks,
|
|
307
|
+
zipOutputAllowedNetworks,
|
|
308
|
+
splitJsNetworks,
|
|
309
|
+
getChannelInjectionSpec,
|
|
310
|
+
getChannelPackPlan,
|
|
311
|
+
buildWindowScript,
|
|
312
|
+
buildChannelScanStubHtml,
|
|
313
|
+
ADIKTEEV_INDEX,
|
|
314
|
+
BIGABID_INDEX,
|
|
315
|
+
};
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const loaderUtils = require('loader-utils');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
|
|
5
|
+
const isObject = (value) => typeof value === 'object' && value !== null;
|
|
6
|
+
const isDataURI = (value) => /^data:/i.test(value);
|
|
7
|
+
|
|
8
|
+
/**
|
|
2
9
|
* A utility function that allows mapping the value for a given key in an object
|
|
3
10
|
* [in place](https://en.wikipedia.org/wiki/In-place_algorithm).
|
|
4
11
|
*
|
|
@@ -13,33 +20,72 @@
|
|
|
13
20
|
* @param {(value: unknown) => Promise<any>} callback
|
|
14
21
|
* The callback that either returns the mapped value, or returns a Promise
|
|
15
22
|
* that resolves to the new value.
|
|
16
|
-
*/
|
|
23
|
+
*/
|
|
24
|
+
async function mapDeep(obj, key, callback) {
|
|
25
|
+
if (Array.isArray(obj)) {
|
|
26
|
+
for (const item of obj) {
|
|
27
|
+
await mapDeep(item, key, callback);
|
|
28
|
+
}
|
|
29
|
+
} else if (isObject(obj)) {
|
|
30
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
31
|
+
if (k === key) {
|
|
32
|
+
obj[k] = await callback(v);
|
|
33
|
+
} else {
|
|
34
|
+
await mapDeep(v, key, callback);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
17
41
|
* @typedef {import(".").GLTFLoaderDefinition} GLTFLoader
|
|
18
42
|
* @this {ThisParameterType<GLTFLoader>}
|
|
19
43
|
* @type {GLTFLoader}
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
*/
|
|
45
|
+
async function gltfLoader(content) {
|
|
46
|
+
// Destructure loader options and set default values:
|
|
47
|
+
const {
|
|
48
|
+
// inline = true,
|
|
49
|
+
// useRelativePaths = true,
|
|
50
|
+
// uriResolver = (module) => String(module.default ?? module),
|
|
51
|
+
// fileName = '[name].[hash:8].[ext]',
|
|
52
|
+
// filePath = '/static/media',
|
|
53
|
+
// publicPath = this._compilation?.outputOptions.publicPath ?? '/',
|
|
54
|
+
context = this.context
|
|
55
|
+
} = this.getOptions();
|
|
56
|
+
|
|
57
|
+
// Parse the glTF data:
|
|
58
|
+
|
|
59
|
+
// console.log(content);
|
|
60
|
+
const data = JSON.parse(content);
|
|
61
|
+
// console.log(data);
|
|
62
|
+
// Iterate over the object and map any URIs:
|
|
63
|
+
await mapDeep(data, 'uri', async (uri) => {
|
|
64
|
+
// Resolve early if the URI cannot be imported as a module:
|
|
65
|
+
if (!loaderUtils.isUrlRequest(uri)) return uri;
|
|
66
|
+
// If the URI is a data URI, print a warning and resolve with the original value:
|
|
67
|
+
if (isDataURI(uri)) {
|
|
68
|
+
return uri;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const requestPath = path.join(context, uri);
|
|
72
|
+
// console.log(requestPath);
|
|
73
|
+
const binContent = fs.readFileSync(requestPath, { encoding: 'base64' });
|
|
74
|
+
return `data:application/octet-stream;base64,${binContent}`;
|
|
75
|
+
});
|
|
76
|
+
// Stringify the updated data:
|
|
77
|
+
const updatedContent = JSON.stringify(data);
|
|
78
|
+
// Interpolate any file name tokens:
|
|
79
|
+
// const interpolatedName = loaderUtils.interpolateName(this, fileName, { content: updatedContent });
|
|
80
|
+
// Join the file path and interpolated name:
|
|
81
|
+
// const interpolatedPath = path.join(filePath, interpolatedName);
|
|
82
|
+
// Emit the file:
|
|
83
|
+
// this.emitFile(interpolatedPath, updatedContent, null);
|
|
84
|
+
// Join all paths together:
|
|
85
|
+
// const fullPath = path.join(publicPath, interpolatedPath);
|
|
86
|
+
// Lastly, resolve with either the JSON data or the full output path:
|
|
87
|
+
// return `export default ${inline ? updatedContent : `"${fullPath}"`}`;
|
|
88
|
+
return `export default ${updatedContent}`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = gltfLoader;
|