@compiled/parcel-optimizer 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  import { Optimizer } from '@parcel/plugin';
2
- declare const _default: Optimizer<unknown>;
2
+ import type { ParcelOptimizerOpts } from './types';
3
+ declare const _default: Optimizer<ParcelOptimizerOpts>;
3
4
  export default _default;
package/dist/index.js CHANGED
@@ -1,10 +1,82 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ const assert_1 = __importDefault(require("assert"));
7
+ const path_1 = require("path");
3
8
  const css_1 = require("@compiled/css");
9
+ const utils_1 = require("@compiled/utils");
4
10
  const plugin_1 = require("@parcel/plugin");
11
+ const posthtml_1 = __importDefault(require("posthtml"));
12
+ const posthtml_insert_at_1 = require("posthtml-insert-at");
13
+ const configFiles = [
14
+ '.compiledcssrc',
15
+ '.compiledcssrc.json',
16
+ 'compiledcss.js',
17
+ 'compiledcss.config.js',
18
+ ];
5
19
  exports.default = new plugin_1.Optimizer({
6
- async optimize({ contents, map }) {
7
- return { contents: (0, css_1.sort)(contents.toString()), map };
20
+ async loadConfig({ config, options }) {
21
+ const conf = await config.getConfigFrom((0, path_1.join)(options.projectRoot, 'index'), configFiles, {
22
+ packageKey: '@compiled/parcel-optimizer',
23
+ });
24
+ const contents = {
25
+ inlineCss: false,
26
+ };
27
+ if (conf) {
28
+ config.invalidateOnStartup();
29
+ Object.assign(contents, conf.contents);
30
+ }
31
+ return contents;
32
+ },
33
+ async optimize({ contents, map, bundle, bundleGraph, options, config }) {
34
+ const { outputFS } = options;
35
+ const styleRules = new Set();
36
+ // Traverse the descendants of HTML bundle
37
+ // Extract the stylesRules from assets
38
+ bundleGraph.traverseBundles((childBundle) => {
39
+ childBundle.traverseAssets((asset) => {
40
+ const rules = asset.meta.styleRules;
41
+ if (rules == null) {
42
+ return;
43
+ }
44
+ (0, assert_1.default)(rules instanceof Array);
45
+ for (const rule of rules) {
46
+ styleRules.add(rule);
47
+ }
48
+ });
49
+ }, bundle);
50
+ if (styleRules.size === 0)
51
+ return { contents, map };
52
+ const stylesheet = (0, css_1.sort)(Array.from(styleRules).join(''));
53
+ let newContents = '';
54
+ if (config.inlineCss) {
55
+ newContents = (await (0, posthtml_1.default)()
56
+ .use((0, posthtml_insert_at_1.insertAt)({
57
+ selector: 'head',
58
+ append: '<style>' + stylesheet + '</style>',
59
+ behavior: 'inside',
60
+ }))
61
+ .process(contents.toString())).html;
62
+ }
63
+ else {
64
+ const { distDir } = bundle.target;
65
+ if (!outputFS.existsSync(distDir)) {
66
+ await outputFS.mkdirp(distDir);
67
+ }
68
+ const cssFileName = (0, path_1.basename)(bundle.displayName, '.html') + '.' + (0, utils_1.hash)(stylesheet) + '.css';
69
+ await outputFS.writeFile((0, path_1.join)(distDir, cssFileName), stylesheet, undefined // for TypeScript
70
+ );
71
+ newContents = (await (0, posthtml_1.default)()
72
+ .use((0, posthtml_insert_at_1.insertAt)({
73
+ selector: 'head',
74
+ append: '<link href="' + bundle.target.publicUrl + cssFileName + '" rel="stylesheet" />',
75
+ behavior: 'inside',
76
+ }))
77
+ .process(contents.toString())).html;
78
+ }
79
+ return { contents: newContents, map };
8
80
  },
9
81
  });
10
82
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,uCAAqC;AACrC,2CAA2C;AAE3C,kBAAe,IAAI,kBAAS,CAAC;IAC3B,KAAK,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE;QAC9B,OAAO,EAAE,QAAQ,EAAE,IAAA,UAAI,EAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC;IACtD,CAAC;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface ParcelOptimizerOpts {
2
+ /**
3
+ * Indicates whether CSS content is inlined in HTML or served as a external .css file.
4
+ * Defaults to `false`.
5
+ */
6
+ inlineCss: boolean;
7
+ }
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compiled/parcel-optimizer",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "description": "A familiar and performant compile time CSS-in-JS library for React.",
5
5
  "bugs": "https://github.com/atlassian-labs/compiled/issues/new?assignees=&labels=bug&template=bug_report.md",
6
6
  "repository": {
@@ -20,14 +20,18 @@
20
20
  ],
21
21
  "dependencies": {
22
22
  "@compiled/css": "^0.8.1",
23
- "@parcel/plugin": "^2.3.1"
23
+ "@compiled/utils": "^0.6.16",
24
+ "@parcel/plugin": "^2.3.1",
25
+ "posthtml": "^0.16.6",
26
+ "posthtml-insert-at": "^0.2.7"
24
27
  },
25
28
  "devDependencies": {
26
29
  "@parcel/core": "^2.3.1",
27
30
  "@parcel/fs": "^2.3.1",
28
31
  "@parcel/types": "^2.3.1",
29
- "ts-node": "^10.4.0",
30
- "tsconfig-paths": "^3.12.0"
32
+ "prettier": "^2.8.1",
33
+ "ts-node": "^10.8.2",
34
+ "tsconfig-paths": "^3.14.1"
31
35
  },
32
36
  "engines": {
33
37
  "parcel": "^2.0.0"
@@ -6,6 +6,7 @@ import { join } from 'path';
6
6
 
7
7
  import Parcel, { createWorkerFarm } from '@parcel/core';
8
8
  import { MemoryFS } from '@parcel/fs';
9
+ import { format } from 'prettier';
9
10
 
10
11
  const rootPath = join(__dirname, '..', '..', '..', '..');
11
12
  const fixtureRoot = join(rootPath, 'fixtures/parcel-optimizer-test-app');
@@ -23,6 +24,7 @@ const parcel = new Parcel({
23
24
  },
24
25
  },
25
26
  workerFarm,
27
+ mode: 'production',
26
28
  });
27
29
 
28
30
  afterAll(() => {
@@ -32,40 +34,45 @@ afterAll(() => {
32
34
  describe('optimizer', () => {
33
35
  it('sorts css rules', async () => {
34
36
  const { changedAssets, bundleGraph } = await parcel.run();
37
+
35
38
  const asset = Array.from(changedAssets.values()).find(
36
- (asset) => asset.filePath === join(fixtureRoot, '/src/styles.css')
39
+ (asset) => asset.filePath === join(fixtureRoot, '/src/index.html')
37
40
  );
38
41
 
39
- const outputCss = await outputFS.readFile(
42
+ const outputHtml = await outputFS.readFile(
40
43
  bundleGraph.getBundlesWithAsset(asset!)[0].filePath,
41
44
  'utf8'
42
45
  );
43
- expect(outputCss).toMatchInlineSnapshot(`
44
- "
45
46
 
46
- .color-blue {
47
- color: blue;
48
- }
47
+ const css = /<style>(.*?)<\/style>/.exec(outputHtml)?.pop();
48
+
49
+ if (!css) throw new Error('No CSS is found.');
49
50
 
50
- .color-blue:focus {
51
+ expect(
52
+ format(css, {
53
+ parser: 'css',
54
+ singleQuote: true,
55
+ })
56
+ ).toMatchInlineSnapshot(`
57
+ "._syaz5scu {
58
+ color: red;
59
+ }
60
+ ._f8pjruxl:focus {
51
61
  color: orange;
52
62
  }
53
-
54
- .color-blue:hover {
63
+ ._30l3bf54:hover {
55
64
  color: green;
56
65
  }
57
-
58
66
  @media screen {
59
- .media-screen-color-red {
67
+ ._43475scu {
60
68
  color: red;
61
69
  }
62
70
  }
63
-
64
71
  @media (min-width: 500px) {
65
- .media-min-width-border {
72
+ ._171dak0l {
66
73
  border: 2px solid red;
67
74
  }
68
- .media-min-width-border:before {
75
+ ._14yn1439 {
69
76
  content: 'large screen';
70
77
  }
71
78
  }
package/src/index.ts CHANGED
@@ -1,8 +1,108 @@
1
+ import assert from 'assert';
2
+ import { join, basename } from 'path';
3
+
1
4
  import { sort } from '@compiled/css';
5
+ import { hash } from '@compiled/utils';
2
6
  import { Optimizer } from '@parcel/plugin';
7
+ import posthtml from 'posthtml';
8
+ import { insertAt } from 'posthtml-insert-at';
9
+
10
+ import type { ParcelOptimizerOpts } from './types';
11
+
12
+ const configFiles = [
13
+ '.compiledcssrc',
14
+ '.compiledcssrc.json',
15
+ 'compiledcss.js',
16
+ 'compiledcss.config.js',
17
+ ];
18
+
19
+ export default new Optimizer<ParcelOptimizerOpts>({
20
+ async loadConfig({ config, options }) {
21
+ const conf = await config.getConfigFrom(join(options.projectRoot, 'index'), configFiles, {
22
+ packageKey: '@compiled/parcel-optimizer',
23
+ });
24
+
25
+ const contents = {
26
+ inlineCss: false,
27
+ };
28
+
29
+ if (conf) {
30
+ config.invalidateOnStartup();
31
+ Object.assign(contents, conf.contents);
32
+ }
33
+
34
+ return contents;
35
+ },
36
+
37
+ async optimize({ contents, map, bundle, bundleGraph, options, config }) {
38
+ const { outputFS } = options;
39
+
40
+ const styleRules = new Set<string>();
41
+
42
+ // Traverse the descendants of HTML bundle
43
+ // Extract the stylesRules from assets
44
+ bundleGraph.traverseBundles((childBundle) => {
45
+ childBundle.traverseAssets((asset) => {
46
+ const rules = asset.meta.styleRules;
47
+ if (rules == null) {
48
+ return;
49
+ }
50
+
51
+ assert(rules instanceof Array);
52
+
53
+ for (const rule of rules) {
54
+ styleRules.add(rule as string);
55
+ }
56
+ });
57
+ }, bundle);
58
+
59
+ if (styleRules.size === 0) return { contents, map };
60
+
61
+ const stylesheet = sort(Array.from(styleRules).join(''));
62
+
63
+ let newContents = '';
64
+
65
+ if (config.inlineCss) {
66
+ newContents = (
67
+ await posthtml()
68
+ .use(
69
+ insertAt({
70
+ selector: 'head',
71
+ append: '<style>' + stylesheet + '</style>',
72
+ behavior: 'inside',
73
+ })
74
+ )
75
+ .process(contents.toString())
76
+ ).html;
77
+ } else {
78
+ const { distDir } = bundle.target;
79
+
80
+ if (!outputFS.existsSync(distDir)) {
81
+ await outputFS.mkdirp(distDir);
82
+ }
83
+
84
+ const cssFileName = basename(bundle.displayName, '.html') + '.' + hash(stylesheet) + '.css';
85
+
86
+ await outputFS.writeFile(
87
+ join(distDir, cssFileName),
88
+ stylesheet,
89
+ undefined // for TypeScript
90
+ );
91
+
92
+ newContents = (
93
+ await posthtml()
94
+ .use(
95
+ insertAt({
96
+ selector: 'head',
97
+ append:
98
+ '<link href="' + bundle.target.publicUrl + cssFileName + '" rel="stylesheet" />',
99
+ behavior: 'inside',
100
+ })
101
+ )
102
+ .process(contents.toString())
103
+ ).html;
104
+ }
3
105
 
4
- export default new Optimizer({
5
- async optimize({ contents, map }) {
6
- return { contents: sort(contents.toString()), map };
106
+ return { contents: newContents, map };
7
107
  },
8
108
  });
package/src/types.ts ADDED
@@ -0,0 +1,7 @@
1
+ export interface ParcelOptimizerOpts {
2
+ /**
3
+ * Indicates whether CSS content is inlined in HTML or served as a external .css file.
4
+ * Defaults to `false`.
5
+ */
6
+ inlineCss: boolean;
7
+ }