UNPKG

3.71 kBJavaScriptView Raw
1'use strict';
2
3const invariant = require('invariant');
4const path = require('path');
5const webpack = require('webpack');
6
7const NodeWatchFileSystem = require('webpack/lib/node/NodeWatchFileSystem');
8const MultiEntryPlugin = require('webpack/lib/MultiEntryPlugin');
9
10const jsxstyleKey = require('./utils/getKey')();
11const resultLoader = require.resolve('./result-loader');
12
13const handledMethods = {
14 // exists: true,
15 // existsSync: true,
16 mkdir: true,
17 mkdirSync: true,
18 mkdirp: true,
19 mkdirpSync: true,
20 readdir: true,
21 readdirSync: true,
22 readFile: true,
23 readFileSync: true,
24 // readlink: true,
25 // readlinkSync: true,
26 rmdir: true,
27 rmdirSync: true,
28 stat: true,
29 statSync: true,
30 unlink: true,
31 unlinkSync: true,
32 writeFile: true,
33 writeFileSync: true,
34};
35
36class JsxstyleWebpackPlugin {
37 constructor(options) {
38 options = Object.assign(
39 {
40 // instead of `require`ing css in every module that uses jsxstyle,
41 // combine all the requires into one CSS file and prepend it to `entry`.
42 __experimental__combineCSS: false,
43 // if the loader encounters a dash-cased element matching a default,
44 // treat it like a lite component instead of an element.
45 __experimental__extremelyLiteMode: false,
46 },
47 options
48 );
49
50 this.memoryFS = new webpack.MemoryOutputFileSystem();
51 this.cacheObject = {};
52
53 // context object that gets passed to each loader.
54 // available in each loader as this[require('./getKey')()]
55 this.ctx = {
56 cacheObject: this.cacheObject,
57 memoryFS: this.memoryFS,
58 fileList: new Set(),
59 compileCallback: null,
60 combineCSS: options.__experimental__combineCSS,
61 extremelyLiteMode: options.__experimental__extremelyLiteMode,
62 };
63 }
64
65 apply(compiler) {
66 const memoryFS = this.memoryFS;
67
68 if (this.ctx.combineCSS) {
69 // TODO: one CSS file per entry
70 compiler.plugin('entry-option', (context, entry) => {
71 const getEntry = (item, name) => {
72 const aggregateFile = path.join(context, name + '.jsxstyle.css');
73 memoryFS.mkdirpSync(context);
74 memoryFS.writeFileSync(aggregateFile, '/* placeholder */');
75
76 return new MultiEntryPlugin(
77 context,
78 [resultLoader + '!' + aggregateFile].concat(item),
79 name
80 );
81 };
82
83 if (typeof entry === 'string' || Array.isArray(entry)) {
84 compiler.apply(getEntry(entry, 'main'));
85 } else if (typeof entry === 'object') {
86 Object.keys(entry).forEach(name => {
87 compiler.apply(getEntry(entry[name], name));
88 });
89 }
90
91 return true;
92 });
93 }
94
95 compiler.plugin('environment', () => {
96 compiler.inputFileSystem = new Proxy(compiler.inputFileSystem, {
97 get: (target, key) => {
98 const value = target[key];
99
100 if (handledMethods.hasOwnProperty(key)) {
101 return function(filePath, ...args) {
102 if (filePath.endsWith('.jsxstyle.css')) {
103 process.stderr.write(key + ' -- ' + filePath);
104 return memoryFS[key](filePath, ...args);
105 }
106 return value.call(this, filePath, ...args);
107 };
108 }
109
110 return value;
111 },
112 });
113
114 compiler.watchFileSystem = new NodeWatchFileSystem(
115 compiler.inputFileSystem
116 );
117 });
118
119 compiler.plugin('compilation', compilation => {
120 compilation.plugin('normal-module-loader', loaderContext => {
121 loaderContext[jsxstyleKey] = this.ctx;
122 });
123
124 if (!this.ctx.combineCSS || compilation.compiler.isChild()) return;
125 });
126 }
127}
128
129module.exports = JsxstyleWebpackPlugin;