1 | var through2 = require("through2");
|
2 | var GulpFile = require("vinyl");
|
3 | var { readFileSync } = require("fs");
|
4 | var { concat } = require("lodash");
|
5 | var glob = require("glob");
|
6 | var { generateIndexHtmlContent } = require("./html");
|
7 |
|
8 | var {
|
9 | generatePreloadFile,
|
10 | findAllImportModules,
|
11 | findAllUi5StandardModules,
|
12 | findAllUi5ViewModules,
|
13 | fetchAllResource,
|
14 | resolveUI5Module,
|
15 | findAllLibraries,
|
16 | readURLFromCache,
|
17 | readBinary,
|
18 | persistCache
|
19 | } = require("./ui5");
|
20 |
|
21 | var path = require("path");
|
22 |
|
23 | var { bundleModule } = require("./thirdparty");
|
24 |
|
25 | var defaultResourceRoot = "https://openui5.hana.ondemand.com/resources/";
|
26 |
|
27 | module.exports = function({
|
28 | sourceDir,
|
29 | preload = false,
|
30 | outputFilePath,
|
31 | thirdpartyLibPath = ".",
|
32 | ui5ResourceRoot = defaultResourceRoot,
|
33 | projectNameSpace: projectNameSpace = "",
|
34 | additionalModules = [],
|
35 | additionalResources = [],
|
36 | theme,
|
37 | title,
|
38 | production = false,
|
39 | withLoadingSpinner = false,
|
40 | bootScript,
|
41 | bootScriptPath,
|
42 | offline = false,
|
43 | library = false
|
44 | }) {
|
45 | if (!ui5ResourceRoot.endsWith("/")) {
|
46 | ui5ResourceRoot = `${ui5ResourceRoot}/`;
|
47 | }
|
48 | var namepath = projectNameSpace.replace(/\./g, "/");
|
49 |
|
50 | var targetJSPath = thirdpartyLibPath;
|
51 |
|
52 | if (targetJSPath.endsWith("/") || targetJSPath.startsWith("/")) {
|
53 | throw new Error(
|
54 | `Not accept path :${thirdpartyLibPath}, please give thirdpartyLibPath like lib |_thirdparty | other/lib`
|
55 | );
|
56 | }
|
57 |
|
58 | return through2.obj(async function(file, encoding, cb) {
|
59 | try {
|
60 |
|
61 | var libs = [];
|
62 |
|
63 | var thirdpartyLibs = [];
|
64 |
|
65 | |
66 |
|
67 |
|
68 | var distinctDeps = new Set(additionalModules);
|
69 |
|
70 |
|
71 | var preloadPromise = new Promise((resolve, reject) => {
|
72 | glob(`${sourceDir}/**/*.?(js|jsx|ts|tsx|mjs)`, async(err, files) => {
|
73 | try {
|
74 |
|
75 | if (err) {
|
76 | reject(err);
|
77 | return;
|
78 | }
|
79 |
|
80 | var allDeps = files.map(f => {
|
81 |
|
82 | var mName = f.replace(sourceDir, namepath);
|
83 | var source = readFileSync(f, { encoding: "utf-8" });
|
84 |
|
85 | return concat(
|
86 | findAllImportModules(source, mName),
|
87 | findAllUi5StandardModules(source, mName)
|
88 | );
|
89 |
|
90 | });
|
91 |
|
92 | concat(...allDeps).forEach(d => {
|
93 | d = path.normalize(d).replace(path.normalize(sourceDir), namepath).replace(/\\/g, "/");
|
94 | if (d.startsWith("sap")) {
|
95 | distinctDeps.add(d);
|
96 | } else if (!d.startsWith(namepath) && !d.startsWith("./") && !d.startsWith("../")) {
|
97 | thirdpartyLibs.push(d);
|
98 | }
|
99 | });
|
100 |
|
101 | resolve();
|
102 |
|
103 | } catch (e) {
|
104 |
|
105 | reject(e);
|
106 |
|
107 | }
|
108 | });
|
109 | });
|
110 |
|
111 |
|
112 | var preloadProjectPromise = new Promise((resolve, reject) => {
|
113 | glob(`${sourceDir}/**/*.+(view|fragment).xml`, async(err, files) => {
|
114 | if (err) {
|
115 | reject(err);
|
116 | } else {
|
117 | var allDeps = await Promise.all(files.map(f => {
|
118 | var mName = f.replace(sourceDir, namepath);
|
119 | var source = readFileSync(f, { encoding: "utf-8" });
|
120 | return findAllUi5ViewModules(source, mName);
|
121 | }));
|
122 | concat(...allDeps).forEach(d => {
|
123 | if (d.startsWith("sap")) {
|
124 | distinctDeps.add(d);
|
125 | }
|
126 | });
|
127 | resolve();
|
128 | }
|
129 | });
|
130 | });
|
131 |
|
132 |
|
133 | await Promise.all([preloadPromise, preloadProjectPromise]);
|
134 |
|
135 | var thirdPartyDepsObject = {};
|
136 | var thirdPartyDepsCode = {};
|
137 |
|
138 | if (thirdpartyLibs) {
|
139 | try {
|
140 | await Promise.all(
|
141 | thirdpartyLibs.map(async packageDepName => {
|
142 |
|
143 | thirdPartyDepsObject[packageDepName] = `${thirdpartyLibPath}/${packageDepName}`;
|
144 |
|
145 | const code = await bundleModule(packageDepName, production);
|
146 | thirdPartyDepsCode[`${packageDepName}`] = code;
|
147 | this.push(
|
148 | new GulpFile({
|
149 | path: `${targetJSPath}/${packageDepName}.js`,
|
150 | contents: Buffer.from(code)
|
151 | })
|
152 | );
|
153 | })
|
154 | );
|
155 | } catch (error) {
|
156 | cb(error);
|
157 | }
|
158 | }
|
159 |
|
160 | if (preload) {
|
161 |
|
162 |
|
163 | var modules = await resolveUI5Module(Array.from(distinctDeps), ui5ResourceRoot);
|
164 |
|
165 | libs = await findAllLibraries(Object.keys(modules));
|
166 |
|
167 | additionalResources = additionalResources.concat(libs.map(l => `${l}/messagebundle_zh_CN.properties`));
|
168 | additionalResources = additionalResources.concat(libs.map(l => `${l}/messagebundle_en.properties`));
|
169 | additionalResources = additionalResources.concat(libs.map(l => `${l}/messagebundle.properties`));
|
170 | additionalResources = additionalResources.concat(libs.map(l => `${l}/messagebundle_en_US.properties`));
|
171 | additionalResources = additionalResources.concat(libs.map(l => `${l}/messagebundle_en_UK.properties`));
|
172 |
|
173 | var resources = await fetchAllResource(additionalResources, ui5ResourceRoot);
|
174 |
|
175 | modules = Object.assign(modules, thirdPartyDepsCode);
|
176 |
|
177 | this.push(
|
178 | new GulpFile({
|
179 | path: "preload.js",
|
180 | contents: Buffer.from(
|
181 | generatePreloadFile(
|
182 | modules,
|
183 | resources
|
184 | )
|
185 | )
|
186 | })
|
187 | );
|
188 |
|
189 | } else {
|
190 | libs = findAllLibraries(distinctDeps);
|
191 | }
|
192 |
|
193 | var cssLinks = [];
|
194 |
|
195 | if (offline) {
|
196 | var uiCoreContent = await readURLFromCache(`${ui5ResourceRoot}sap-ui-core.js`);
|
197 | var corePreloadContent = await readURLFromCache(`${ui5ResourceRoot}sap/ui/core/library-preload.js`);
|
198 |
|
199 | var offlineFiles = [
|
200 | `sap/ui/core/themes/${theme}/fonts/72-Regular.woff2`,
|
201 | `sap/ui/core/themes/${theme}/fonts/72-Regular.woff`,
|
202 | `sap/ui/core/themes/${theme}/fonts/72-Regular-full.woff2`,
|
203 | `sap/ui/core/themes/${theme}/fonts/72-Regular-full.woff`,
|
204 | `sap/ui/core/themes/${theme}/fonts/72-Bold.woff2`,
|
205 | `sap/ui/core/themes/${theme}/fonts/72-Bold.woff`,
|
206 | `sap/ui/core/themes/${theme}/fonts/72-Bold-full.woff2`,
|
207 | `sap/ui/core/themes/${theme}/fonts/72-Bold-full.woff`,
|
208 | "sap/ui/core/themes/base/fonts/SAP-icons.woff2",
|
209 | "sap/ui/core/themes/base/fonts/SAP-icons.woff",
|
210 | "sap/ui/core/themes/base/fonts/SAP-icons.ttf",
|
211 | "sap/ui/core/cldr/zh_CN.json",
|
212 | "sap-ui-version.json"
|
213 | ];
|
214 |
|
215 | var files = await Promise.all(
|
216 | concat(
|
217 | libs.map(async l => ({
|
218 | target: `resources/${l}/themes/${theme}/library.css`,
|
219 | content: Buffer.from(await readURLFromCache(`${ui5ResourceRoot}${l}/themes/${theme}/library.css`))
|
220 | })),
|
221 | libs.map(async l => ({
|
222 | target: `resources/${l}/themes/${theme}/library-parameters.json`,
|
223 | content: Buffer.from(await readURLFromCache(`${ui5ResourceRoot}${l}/themes/${theme}/library-parameters.json`))
|
224 | })),
|
225 | offlineFiles.map(async fontPath => ({ target: `resources/${fontPath}`, content: await readBinary(`${ui5ResourceRoot}${fontPath}`) }))
|
226 | )
|
227 | );
|
228 |
|
229 |
|
230 | this.push(
|
231 | new GulpFile({
|
232 | path: "resources/sap-ui-core.js",
|
233 | contents: Buffer.from(uiCoreContent)
|
234 | })
|
235 | );
|
236 | this.push(
|
237 | new GulpFile({
|
238 | path: "resources/sap/ui/core/library-preload.js",
|
239 | contents: Buffer.from(corePreloadContent)
|
240 | })
|
241 | );
|
242 | files.forEach(f => {
|
243 | this.push(
|
244 | new GulpFile({
|
245 | path: f.target,
|
246 | contents: f.content
|
247 | })
|
248 | );
|
249 | });
|
250 | cssLinks = libs.map(l => `./resources/${l}/themes/${theme}/library.css`);
|
251 | } else {
|
252 | cssLinks = libs.map(l => `${ui5ResourceRoot}${l}/themes/${theme}/library.css`);
|
253 | }
|
254 |
|
255 | if (!library) {
|
256 |
|
257 | var indexHtml = generateIndexHtmlContent({
|
258 | resourceRoot: ui5ResourceRoot,
|
259 | projectNameSpace: projectNameSpace,
|
260 | theme: theme,
|
261 | title: title,
|
262 | bootScript,
|
263 | bootScriptPath,
|
264 | preload,
|
265 | offline,
|
266 | withLoadingSpinner,
|
267 | inlineCssLink: cssLinks,
|
268 | resourceRoots: {
|
269 | [projectNameSpace]: ".",
|
270 | ...thirdPartyDepsObject
|
271 | }
|
272 | });
|
273 |
|
274 | this.push(
|
275 | new GulpFile({
|
276 | path: outputFilePath || "index.html",
|
277 | contents: Buffer.from(indexHtml)
|
278 | })
|
279 | );
|
280 |
|
281 | }
|
282 |
|
283 |
|
284 | persistCache.Persist();
|
285 |
|
286 | cb();
|
287 |
|
288 | } catch (err) {
|
289 |
|
290 | cb(err);
|
291 |
|
292 | }
|
293 | });
|
294 |
|
295 | };
|
296 |
|
297 | module.exports.componentPreload = require("./component_preload");
|