1 | "use strict";
|
2 |
|
3 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
4 |
|
5 | const _crypto = require("crypto");
|
6 | const _fs = require("fs");
|
7 | const _path = require("path");
|
8 |
|
9 | const async = require("neo-async");
|
10 | const cheerio = require("cheerio");
|
11 | const ejs = require("ejs");
|
12 | const merge = require("webpack-merge");
|
13 | const mkdirp = require("mkdirp");
|
14 | const tmp = require("tmp");
|
15 | const touch = require("touch");
|
16 | const rimraf = require("rimraf");
|
17 | const webpack = require("webpack");
|
18 |
|
19 | const defaultAntwar = require("../config/default-antwar");
|
20 | const mergeConfiguration = require("../libs/merge-configuration");
|
21 |
|
22 | const cwd = process.cwd();
|
23 |
|
24 | module.exports = function writePages({ configurationPaths, environment, pages, outputPath, templates }, finalCb) {
|
25 | const antwarConfiguration = mergeConfiguration(defaultAntwar(), require(configurationPaths.antwar)(environment));
|
26 |
|
27 | async.each(pages, ({ page, path }, cb) => processPage({
|
28 | configurationPaths,
|
29 | antwarConfiguration,
|
30 | page,
|
31 | path,
|
32 | outputPath,
|
33 | templates
|
34 | }, cb), finalCb);
|
35 | };
|
36 |
|
37 | function processPage({
|
38 | configurationPaths,
|
39 | antwarConfiguration,
|
40 | page = "",
|
41 | outputPath = "",
|
42 | path = "",
|
43 | templates = {} // page/interactive/interactiveIndex
|
44 | }, cb) {
|
45 | const renderPage = require(_path.join(outputPath, "site.js")).renderPage;
|
46 | const console = antwarConfiguration.console;
|
47 |
|
48 | renderPage(page, function (err, { html, page, context }) {
|
49 | if (err) {
|
50 | return cb(err);
|
51 | }
|
52 |
|
53 | const $ = cheerio.load(html);
|
54 | const components = $(".interactive").map((i, el) => {
|
55 | const $el = $(el);
|
56 | const id = $el.attr("id");
|
57 | const props = $el.data("props");
|
58 |
|
59 | return {
|
60 | id,
|
61 | name: `Interactive${i}`,
|
62 | path: _path.join(cwd, id),
|
63 | props: convertToJS(props)
|
64 | };
|
65 | }).get();
|
66 | const jsFiles = [];
|
67 |
|
68 | if (components.length) {
|
69 |
|
70 | components.forEach(component => {
|
71 | if (!_fs.existsSync(component.path)) {
|
72 | console.log("Failed to find", component.path);
|
73 | }
|
74 | });
|
75 |
|
76 |
|
77 |
|
78 |
|
79 | const filename = calculateMd5(_path.relative(cwd, path).split("/").filter(a => a).slice(0, -1).join("/") + components.map(c => c.id + "=" + c.props).join(""));
|
80 | const interactivePath = _path.join(outputPath, `${filename}.js`);
|
81 |
|
82 |
|
83 | jsFiles.push(`/${filename}.js`);
|
84 |
|
85 |
|
86 | if (!_fs.existsSync(interactivePath)) {
|
87 | const interactiveIndexEntry = ejs.compile(templates.interactiveIndex.file)({
|
88 | components
|
89 | });
|
90 | const entry = ejs.compile(templates.interactive.file)({
|
91 | components
|
92 | });
|
93 |
|
94 |
|
95 | touch.sync(interactivePath);
|
96 |
|
97 |
|
98 | const interactiveEntryTmpFile = tmp.fileSync();
|
99 | const entryTmpFile = tmp.fileSync();
|
100 |
|
101 |
|
102 | _fs.writeFileSync(interactiveEntryTmpFile.name, interactiveIndexEntry);
|
103 | _fs.writeFileSync(entryTmpFile.name, entry);
|
104 |
|
105 | const interactiveConfig = require(configurationPaths.webpack)("interactive");
|
106 | const webpackConfig = merge(interactiveConfig, {
|
107 | mode: "production",
|
108 | resolve: {
|
109 | modules: [cwd, _path.join(cwd, "node_modules")],
|
110 | alias: generateAliases(components)
|
111 | },
|
112 | resolveLoader: {
|
113 | modules: [cwd, _path.join(cwd, "node_modules")]
|
114 | }
|
115 | });
|
116 |
|
117 | const interactiveIndexEntryName = `${filename}-interactive-entry`;
|
118 |
|
119 |
|
120 | webpackConfig.entry = {
|
121 | [interactiveIndexEntryName]: interactiveEntryTmpFile.name,
|
122 | [filename]: entryTmpFile.name
|
123 | };
|
124 |
|
125 |
|
126 | webpackConfig.output = merge(interactiveConfig.output, {
|
127 | filename: "[name].js",
|
128 | path: outputPath,
|
129 | publicPath: "/",
|
130 | libraryTarget: "umd",
|
131 | globalObject: "this"
|
132 | });
|
133 |
|
134 | return webpack(webpackConfig, (err2, stats) => {
|
135 | if (err2) {
|
136 | return cb(err2);
|
137 | }
|
138 |
|
139 | if (stats.hasErrors()) {
|
140 | return cb(stats.toString("errors-only"));
|
141 | }
|
142 |
|
143 | const interactiveIndexPath = _path.join(outputPath, interactiveIndexEntryName);
|
144 | const interactiveComponents = require(interactiveIndexPath);
|
145 | const renderErrors = [];
|
146 |
|
147 |
|
148 | $(".interactive").each((i, el) => {
|
149 | const $el = $(el);
|
150 | const props = $el.data("props");
|
151 |
|
152 | try {
|
153 | $el.html(antwarConfiguration.render.interactive({
|
154 | component: interactiveComponents[`Interactive${i}`],
|
155 | props
|
156 | }));
|
157 | } catch (renderErr) {
|
158 | renderErrors.push(renderErr);
|
159 | }
|
160 | });
|
161 |
|
162 | if (renderErrors.length) {
|
163 | return cb(renderErrors[0]);
|
164 | }
|
165 |
|
166 | rimraf.sync(interactiveIndexPath + ".*");
|
167 |
|
168 |
|
169 | const data = ejs.compile(templates.page.file)({
|
170 | htmlWebpackPlugin: {
|
171 | options: {
|
172 | context: _extends({}, context, page.file, templates.page, {
|
173 | jsFiles: [...templates.page.jsFiles, ...jsFiles]
|
174 | })
|
175 | }
|
176 | },
|
177 | webpackConfig: {
|
178 | html: $.html()
|
179 | }
|
180 | });
|
181 |
|
182 | return writePage({ console, path, data, page }, cb);
|
183 | });
|
184 | }
|
185 | }
|
186 |
|
187 |
|
188 | const data = ejs.compile(templates.page.file)({
|
189 | htmlWebpackPlugin: {
|
190 | options: {
|
191 | context: _extends({}, context, page.file, templates.page, {
|
192 | jsFiles: [...templates.page.jsFiles, ...jsFiles]
|
193 | })
|
194 | }
|
195 | },
|
196 | webpackConfig: {
|
197 | html
|
198 | }
|
199 | });
|
200 |
|
201 | return writePage({ console, path, data }, cb);
|
202 | });
|
203 | }
|
204 |
|
205 | function convertToJS(props) {
|
206 | let ret = "";
|
207 |
|
208 | Object.keys(props).forEach(prop => {
|
209 | const v = props[prop];
|
210 |
|
211 | ret += `${prop}: ${JSON.stringify(v)},`;
|
212 | });
|
213 |
|
214 | return `{${ret}}`;
|
215 | }
|
216 |
|
217 | function generateAliases(components) {
|
218 | const ret = {};
|
219 |
|
220 | components.forEach(({ id, path }) => {
|
221 | ret[id] = path;
|
222 | });
|
223 |
|
224 | return ret;
|
225 | }
|
226 |
|
227 | function writePage({ console, path, data }, cb) {
|
228 | mkdirp(_path.dirname(path), function (err) {
|
229 | if (err) {
|
230 | return cb(err);
|
231 | }
|
232 |
|
233 | return _fs.writeFile(path, data, function (err2) {
|
234 | if (err2) {
|
235 | return cb(err2);
|
236 | }
|
237 |
|
238 | console.log("Finished writing page", path);
|
239 |
|
240 | return cb();
|
241 | });
|
242 | });
|
243 | }
|
244 |
|
245 | function calculateMd5(input) {
|
246 | return _crypto.createHash("md5").update(input).digest("hex");
|
247 | } |
\ | No newline at end of file |