UNPKG

wordpress-shortcode-webpack-plugin

Version:
337 lines (336 loc) 17 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.WordpressShortcodeWebpackPlugin = void 0; var webpack_manifest_plugin_1 = require("webpack-manifest-plugin"); var uuid_1 = require("uuid"); var path_1 = require("path"); var template_1 = require("./template"); var yazl_1 = __importDefault(require("yazl")); var WordpressShortcodeWebpackPlugin = /** @class */ (function () { function WordpressShortcodeWebpackPlugin(options) { this.options = options; if (!options.wordpressPluginName) { throw new Error('wordpressPluginName is required'); } var defaults = { shortcodePrefix: options.wordpressPluginName, pluginTemplate: path_1.resolve(__dirname, 'default-template.php'), headerFields: {}, entryToRootId: {}, }; this.options = Object.assign({}, defaults, options); } WordpressShortcodeWebpackPlugin.prototype.apply = function (compiler) { var _this = this; var pluginName = WordpressShortcodeWebpackPlugin.name; var wpPluginName = this.options.wordpressPluginName; var dummyManifestFilename = uuid_1.v4(); // Naming convention required by Wordpress var outputFileName = path_1.join(wpPluginName, wpPluginName + ".php"); // Create a custom manifest using WebpackManifestPlugin. createManifestPlugin(dummyManifestFilename, wpPluginName, compiler); var isWp5 = 'webpack' in compiler; if (!isWp5) { var webpack4Compiler_1 = compiler; webpack4Compiler_1.hooks.emit.tap(pluginName, function (compilation) { return webpack4CompilationHook(compilation, webpack4Compiler_1, pluginName, wpPluginName, outputFileName, _this.options); }); // This is a little janky but we've got to do it based on an // interaction between Webpack 4 and WebpackManifestPlugin webpack4Compiler_1.hooks.emit.tapPromise({ name: pluginName, stage: Infinity, }, function (compilation) { return webpack4ZipFile(compilation, outputFileName, wpPluginName); }); } else { var webpack5Compiler_1 = compiler; webpack5Compiler_1.hooks.thisCompilation.tap(pluginName, function (compilation) { return webpack5CompilationHook(compilation, webpack5Compiler_1, pluginName, wpPluginName, outputFileName, _this.options); }); } }; return WordpressShortcodeWebpackPlugin; }()); exports.WordpressShortcodeWebpackPlugin = WordpressShortcodeWebpackPlugin; // Compilation hook for Webpack 5. There are subtle differences between the // interface that Webpack exposes for plugins between 4 and 5. The hook // names are different, the way you add and remove assets is different, and // the types of the compiler and compilation are different. To paper over the // difference, we maintain slightly different versions of the hook for WP4 and 5. function webpack5CompilationHook(compilation, compiler, pluginName, wpPluginName, outputFileName, options) { var _this = this; var _a = webpack_manifest_plugin_1.getCompilerHooks( // @ts-ignore compiler), beforeEmit = _a.beforeEmit, afterEmit = _a.afterEmit; var RawSource = compiler.webpack.sources.RawSource; beforeEmit.tap(pluginName, function (manifest) { var e_1, _a; // This is the "main" file of the Wordpress plugin. We do all of the // work of applying our header, manifest, and loaders to the specified // template here. var pluginFile = template_1.generatePluginFile(wpPluginName, manifest, options, // @ts-ignore compiler); compilation.emitAsset(outputFileName, new RawSource(pluginFile)); try { // We're also gonna fork all entry content into our plugin folder // We don't know what other apps are being deployed out of this build // folder so we opt to copy them. for (var _b = __values(Object.keys(compilation.assets)), _c = _b.next(); !_c.done; _c = _b.next()) { var file = _c.value; // Skip any file in the plugin directory already if (file.startsWith(wpPluginName)) continue; var dupedFileName = path_1.join(wpPluginName, 'assets', file); compilation.emitAsset(dupedFileName, new RawSource(compilation.assets[file].source())); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } }); // We do this because we don't have a way to asynchronously process the output // generated during the `beforeEmit` hook provided by WebpackManifestPlugin. // So, we use the `additionalAssets` flag, which runs a second time // whenever any `processAssets` hook adds more files to the compilation. // This is a bit of a hack, and will be fixed by https://github.com/shellscape/webpack-manifest-plugin/pulls // See https://github.com/shellscape/webpack-manifest-plugin/issues/262 for more context. // We need to do asynchronous work because we want to create an archive // of the Wordpress plugin and all the good Zip libraries are either // promise or stream-based. // We use the raw number here so we don't take a direct dependency // on Webpack in our output. Good for bundle size, good for us. // From Compilation.PROCESS_ASSETS_STAGE_REPORT var PROCESS_ASSETS_STAGE_REPORT = 5000; compilation.hooks.processAssets.tapPromise({ stage: PROCESS_ASSETS_STAGE_REPORT, name: pluginName, additionalAssets: true, }, function (assets) { return __awaiter(_this, void 0, void 0, function () { var zipFile, zipFileName; return __generator(this, function (_a) { switch (_a.label) { case 0: // We use this to test that this particular invocation of `processAssets` is // the one triggered by out `beforeEmit` hook. if (!assets[outputFileName]) return [2 /*return*/]; return [4 /*yield*/, createZipFile(assets, wpPluginName)]; case 1: zipFile = _a.sent(); zipFileName = wpPluginName + ".zip"; compilation.emitAsset(zipFileName, new RawSource(zipFile)); return [2 /*return*/]; } }); }); }); // Clean up our manifest after we're done with it afterEmit.tap(pluginName, function (manifest) { compilation.deleteAsset(manifest.id); }); } // Compilation hook for Webpack 4. Deprecated. function webpack4CompilationHook(compilation, compiler, pluginName, wpPluginName, outputFileName, options) { var _a = webpack_manifest_plugin_1.getCompilerHooks( // @ts-ignore compiler), beforeEmit = _a.beforeEmit, afterEmit = _a.afterEmit; beforeEmit.tap(pluginName, function (manifest) { // This is the "main" file of the Wordpress plugin. We do all of the // work of applying our header, manifest, and loaders to the specified // template here. var pluginFile = template_1.generatePluginFile(wpPluginName, manifest, options, // @ts-ignore compiler); compilation.assets[outputFileName] = { source: function () { return pluginFile; }, size: function () { return pluginFile.length; }, }; // We're also gonna fork all entry content into our plugin folder // We don't know what other apps are being deployed out of this build // folder so we opt to copy them. for (var file in compilation.assets) { // Skip any file in the plugin directory already if (file.startsWith(wpPluginName)) continue; var dupedFileName = path_1.join(wpPluginName, 'assets', file); compilation.assets[dupedFileName] = compilation.assets[file]; } }); // Clean up our manifest after we're done with it afterEmit.tap(pluginName, function (manifest) { delete compilation.assets[manifest.id]; }); } function webpack4ZipFile(compilation, outputFileName, wpPluginName) { return __awaiter(this, void 0, void 0, function () { var zipFile, zipFileName; return __generator(this, function (_a) { switch (_a.label) { case 0: // We do this because we don't have a way to asynchronously process the output // generated during the `beforeEmit` hook provided by WebpackManifestPlugin. // So, we use the `additionalAssets` flag, which runs a second time // whenever any `processAssets` hook adds more files to the compilation. // This is a bit of a hack, and will be fixed by https://github.com/shellscape/webpack-manifest-plugin/pulls // See https://github.com/shellscape/webpack-manifest-plugin/issues/262 for more context. // We need to do asynchronous work because we want to create an archive // of the Wordpress plugin and all the good Zip libraries are either // promise or stream-based. // We use this to test that this particular invocation of `processAssets` is // the one triggered by out `beforeEmit` hook. if (!compilation.assets[outputFileName]) return [2 /*return*/]; return [4 /*yield*/, createZipFile(compilation.assets, wpPluginName)]; case 1: zipFile = _a.sent(); zipFileName = wpPluginName + ".zip"; compilation.assets[zipFileName] = { source: function () { return zipFile; }, size: function () { return zipFile.length; }, }; return [2 /*return*/]; } }); }); } // We're going to create a new instance of WebpackManifestPlugin that allows us to create // a manifest to our specifications. This is a simple way for us to figure out // the "real" list of files that are generated in our build. function createManifestPlugin(manifestName, wpPluginName, compiler) { new webpack_manifest_plugin_1.WebpackManifestPlugin({ // We don't actually care about the file that gets written, we're going to make a unique name so we can delete it fileName: manifestName, generate: function (_, __, entries) { var entrypointFiles = {}; Object.keys(entries).forEach(function (entrypoint) { entrypointFiles[entrypoint] = entries[entrypoint].filter(function (fileName) { return !fileName.endsWith('.map'); }); }); return { entries: entrypointFiles, // Bit of a hack so we can clean this file up by ID later id: manifestName, }; }, // @ts-ignore }).apply(compiler); } function createZipFile( // Type CompilationAssets, but Webpack doesn't export the type :( assets, wpPluginName) { return __awaiter(this, void 0, void 0, function () { var archive, _a, _b, _c, assetPath, asset, assetBuffer; var e_2, _d; return __generator(this, function (_e) { archive = new yazl_1.default.ZipFile(); try { for (_a = __values(Object.entries(assets)), _b = _a.next(); !_b.done; _b = _a.next()) { _c = __read(_b.value, 2), assetPath = _c[0], asset = _c[1]; // Make sure no other assets got caught up in this run if (!assetPath.startsWith(wpPluginName)) continue; assetBuffer = 'buffer' in asset ? asset.buffer() : Buffer.from(asset.source()); // OK we're dealing with something we want to zip archive.addBuffer(assetBuffer, // TODO: Clean this up assetPath.replace(wpPluginName + "/", '')); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_b && !_b.done && (_d = _a.return)) _d.call(_a); } finally { if (e_2) throw e_2.error; } } archive.end(); return [2 /*return*/, new Promise(function (resolve, reject) { var bufs = []; archive.outputStream.on('data', function (buf) { return bufs.push(buf); }); archive.outputStream.on('error', function (error) { return reject(error); }); archive.outputStream.on('end', function () { var outFile = Buffer.concat(bufs); resolve(outFile); }); })]; }); }); }