UNPKG

3.56 kBJavaScriptView Raw
1"use strict";
2
3const fs = require("fs-extra");
4const path = require("path");
5const nunjucks = require("nunjucks");
6
7const pluginName = "NunjucksWebpackPlugin";
8
9class NunjucksWebpackPlugin {
10 constructor(options) {
11 this.options = Object.assign(
12 {},
13 {
14 configure: {
15 options: {},
16 path: ""
17 },
18 templates: []
19 },
20 options || {}
21 );
22
23 if (
24 !Array.isArray(this.options.templates) ||
25 this.options.templates.length === 0
26 ) {
27 throw new Error("Options `templates` must be an empty array");
28 }
29 }
30
31 apply(compiler) {
32 const fileDependencies = [];
33
34 let output = compiler.options.output.path;
35
36 if (
37 output === "/" &&
38 compiler.options.devServer &&
39 compiler.options.devServer.outputPath
40 ) {
41 output = compiler.options.devServer.outputPath;
42 }
43
44 const emitCallback = (compilation, callback) => {
45 const configure =
46 this.options.configure instanceof nunjucks.Environment
47 ? this.options.configure
48 : nunjucks.configure(
49 this.options.configure.path,
50 this.options.configure.options
51 );
52
53 const promises = [];
54
55 this.options.templates.forEach(template => {
56 if (!template.from) {
57 throw new Error("Each template should have `from` option");
58 }
59
60 if (!template.to) {
61 throw new Error("Each template should have `to` option");
62 }
63
64 if (fileDependencies.indexOf(template.from) === -1) {
65 fileDependencies.push(template.from);
66 }
67
68 const res = configure.render(
69 template.from,
70 template.context ? template.context : null,
71 template.callback ? template.callback : null
72 );
73
74 let webpackTo = template.to;
75
76 if (path.isAbsolute(webpackTo)) {
77 webpackTo = path.relative(output, webpackTo);
78 }
79
80 const source = {
81 size: () => res.length,
82 source: () => res
83 };
84
85 compilation.assets[webpackTo] = source;
86
87 if (template.writeToFileEmit) {
88 const fileDest = path.join(output, webpackTo);
89
90 promises.push(fs.outputFile(fileDest, source.source()));
91 }
92 });
93
94 return (
95 Promise.all(promises)
96 // eslint-disable-next-line promise/no-callback-in-promise
97 .then(() => callback())
98 .catch(error => {
99 compilation.errors.push(error);
100
101 // eslint-disable-next-line promise/no-callback-in-promise
102 return callback();
103 })
104 );
105 };
106
107 const afterEmitCallback = (compilation, callback) => {
108 let compilationFileDependencies = compilation.fileDependencies;
109 let addFileDependency = file => compilation.fileDependencies.add(file);
110
111 if (Array.isArray(compilation.fileDependencies)) {
112 compilationFileDependencies = new Set(compilation.fileDependencies);
113 addFileDependency = file => compilation.fileDependencies.push(file);
114 }
115
116 for (const file of fileDependencies) {
117 if (!compilationFileDependencies.has(file)) {
118 addFileDependency(file);
119 }
120 }
121
122 return callback();
123 };
124
125 if (compiler.hooks) {
126 compiler.hooks.emit.tapAsync(pluginName, emitCallback);
127 compiler.hooks.afterEmit.tapAsync(pluginName, afterEmitCallback);
128 } else {
129 compiler.plugin("emit", emitCallback);
130 compiler.plugin("after-emit", afterEmitCallback);
131 }
132 }
133}
134
135module.exports = NunjucksWebpackPlugin;