Skip to content

Commit

Permalink
(feat): add PURE annotation for DCE (#48)
Browse files Browse the repository at this point in the history
* (feat): add PURE annotation for DCE

* Create nasty-ways-smell.md
  • Loading branch information
kuldeepkeshwar committed Jul 28, 2020
1 parent 908d2c9 commit 002e3f5
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 101 deletions.
9 changes: 9 additions & 0 deletions .changeset/nasty-ways-smell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"babel-plugin-filbert": patch
"@filbert-js/core": patch
"@filbert-js/website": patch
---

- Prepend #__PURE__ comment to help minifiers with dead code elimination (=DCE)
- Remove `StyleSheetContext` from `styled` api
- Refactored website(sidebar)
30 changes: 29 additions & 1 deletion packages/babel-plugin-filbert/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,43 @@
/**
* Prepend #__PURE__ comment to help minifiers with
* dead code elminiation (=DCE)
* thanks to @marvinhagemeister / @cristianbote
*/
function prependPureComment(node) {
const comments = node.leadingComments || (node.leadingComments = []);
comments.push({
type: 'CommentBlock',
value: '#__PURE__',
});
}
const tags = ['css', 'keyframes'];
module.exports = function({ types: t }, options = {}) {
const name = options.name || 'styled';

// Enable pure by default if it is not set by the user
const pure = !('pure' in options) ? true : options.pure;
return {
name: 'transform-filbert',
visitor: {
TaggedTemplateExpression(path, state) {
if (
t.isIdentifier(path.node.tag) &&
tags.includes(path.node.tag.name)
) {
pure && prependPureComment(path.node);
} else if (
t.isIdentifier(path.node.tag.callee) &&
path.node.tag.callee.name === name
) {
pure && prependPureComment(path.node);
}
},
MemberExpression: {
exit(path) {
const node = path.node;
if (!t.isIdentifier(node.object) || node.object.name !== name) {
return;
}
pure && prependPureComment(path.node);
let property = node.property;
if (t.isIdentifier(property)) {
property = t.stringLiteral(property.name);
Expand Down
23 changes: 8 additions & 15 deletions packages/core/src/hooks.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
import { TYPES_GLOBAL, TYPES_STYLES } from '@filbert-js/types';

import React from 'react';
import { StyleSheetContext } from '@filbert-js/style-sheet-context';
import { __sheet } from '@filbert-js/style-sheet-context';

// invoke callback if value changes b/w render cycles

export function useGlobalStylesheet(id, styles) {
const stylesheet = React.useContext(StyleSheetContext);
const stylesheetRef = React.useRef();
stylesheetRef.current = stylesheet;
stylesheetRef.current.createGlobalStyles(id, styles);
__sheet.createGlobalStyles(id, styles);

React.useEffect(
() => {
stylesheetRef.current.createGlobalStyles(id, styles);
__sheet.createGlobalStyles(id, styles);
},
[styles, id],
);

React.useEffect(
() => {
return () => stylesheetRef.current.removeStyles(id, TYPES_GLOBAL);
return () => __sheet.removeStyles(id, TYPES_GLOBAL);
},
[id],
);
Expand All @@ -33,13 +30,10 @@ export function useStylesheet(
sourceOrder,
label,
) {
const sheet = React.useContext(StyleSheetContext);
const latestRef = React.useRef();

const stylesheetRef = React.useRef();
stylesheetRef.current = sheet;
keyframes.forEach((frame) => sheet.createKeyframes(frame));
stylesheetRef.current.createStyles(className, styles, sourceOrder, label);
keyframes.forEach((frame) => __sheet.createKeyframes(frame));
__sheet.createStyles(className, styles, sourceOrder, label);

latestRef.current = className;

Expand All @@ -49,15 +43,14 @@ export function useStylesheet(
return () => {
const latest = latestRef.current;
if (previous !== latest) {
stylesheetRef.current.removeStyles(previous, TYPES_STYLES);
__sheet.removeStyles(previous, TYPES_STYLES);
}
};
},
[className],
);

React.useEffect(() => {
return () =>
stylesheetRef.current.removeStyles(latestRef.current, TYPES_STYLES);
return () => __sheet.removeStyles(latestRef.current, TYPES_STYLES);
}, []);
}
10 changes: 2 additions & 8 deletions website/gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,7 @@ module.exports = {
path: `${__dirname}/docs`,
},
},
{
resolve: 'gatsby-source-filesystem',
options: {
name: 'docs_yaml',
path: `${__dirname}/docs/docs.yaml`,
},
},

{
resolve: `gatsby-plugin-manifest`,
options: {
Expand Down Expand Up @@ -82,7 +76,7 @@ module.exports = {
trackingId: 'UA-171640923-1',
},
},
`gatsby-transformer-yaml`,

'gatsby-plugin-filbert',
`gatsby-plugin-react-helmet`,
'gatsby-plugin-sharp',
Expand Down
88 changes: 50 additions & 38 deletions website/gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ const path = require('path');
const docsYaml = require('./docs-yaml')();
const _ = require('lodash');

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
.BundleAnalyzerPlugin;
global.Babel = require('babel-standalone');

exports.onCreateWebpackConfig = ({ stage, actions, plugins, getConfig }) => {
Expand Down Expand Up @@ -57,6 +55,41 @@ exports.onCreateWebpackConfig = ({ stage, actions, plugins, getConfig }) => {
function isCapital(word) {
return word.toUpperCase() === word;
}

const docs = [];
docsYaml.forEach(({ items, title }) => {
const isPackage = title === 'Packages';
items.forEach((name) => {
const fileName = isCapital(name) ? name : _.kebabCase(name);
const prefix = 'Getting Started' === title ? 'docs' : _.kebabCase(title);
docs.push({
isPackage: isPackage,
name: name,
fileName: isPackage ? name : fileName,
slug: `${prefix}/${isPackage ? name : fileName}`,
group: title,
});
});
});

exports.sourceNodes = ({ actions, createNodeId, createContentDigest }) => {
const { createNode } = actions;

// Data can come from anywhere, but for now create it manually
const data = { items: docs };
const nodeMeta = {
id: createNodeId(`docs-map`),
parent: null,
children: [],
internal: {
type: `DocMap`,
contentDigest: createContentDigest(data),
},
};

const node = Object.assign({}, data, nodeMeta);
createNode(node);
};
exports.createPages = async ({ actions }) => {
const { createPage, createRedirect } = actions;
createRedirect({
Expand All @@ -67,31 +100,14 @@ exports.createPages = async ({ actions }) => {
});
const docTemplate = require.resolve(`./src/templates/doc.js`);
const packageTemplate = require.resolve(`./src/templates/package.js`);
docsYaml.forEach(({ items, title }) => {
if (title === 'Packages') {
items.forEach((slug) => {
createPage({
path: `packages/${slug}`,
component: packageTemplate,
context: {
slug: slug,
},
});
});
} else {
items.forEach((item) => {
const slug = isCapital(item) ? item : _.kebabCase(item);
const prefix =
'Getting Started' === title ? 'docs' : _.kebabCase(title);
createPage({
path: `${prefix}/${slug}`,
component: docTemplate,
context: {
slug: slug,
},
});
});
}
docs.forEach(({ slug, isPackage }) => {
createPage({
path: slug,
component: isPackage ? packageTemplate : docTemplate,
context: {
slug: slug,
},
});
});
};
// Add custom url pathname for blog posts.
Expand All @@ -100,30 +116,26 @@ exports.onCreateNode = async ({ node, actions, getNode }) => {

if (node.internal.type === `Mdx` && typeof node.slug === `undefined`) {
const fileNode = getNode(node.parent);

let value;
if (fileNode.name === 'README') {
const pkgName = getNameForPackage(fileNode.absolutePath);
if (pkgName === 'root') {
value = 'introduction';
} else if (pkgName) {
value = pkgName;
createNodeField({
node,
name: `isPackage`,
value: true,
});
} else {
value = fileNode.name;
value = pkgName;
}
} else {
value = fileNode.name;
}
const title = isCapital(value) ? value : _.startCase(value);

const [doc] = docs.filter((doc) => doc.fileName === value);
const title = doc.name;
const slug = doc.slug;

createNodeField({
node,
name: `slug`,
value: value,
value: slug,
});
createNodeField({
node,
Expand Down
61 changes: 22 additions & 39 deletions website/src/components/Sidebar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,55 +20,43 @@ const MenuHeading = styled.div`
margin-bottom: 1rem;
`;
export const Sidebar = () => {
const { allMdx, allDocsYaml } = useStaticQuery(graphql`
query allDocsYaml {
allDocsYaml {
const { allDocMap } = useStaticQuery(graphql`
query Sidebar {
allDocMap {
nodes {
items
title
}
}
allMdx {
nodes {
fields {
items {
group
name
slug
title
isPackage
}
}
}
}
`);
const linkMap = allMdx.nodes.reduce(
(agg, { fields: { slug, title, isPackage } }) => {
if (isPackage) {
agg[slug] = { slug, title };
} else {
agg[title] = { slug, title };
}

return agg;
},
{},
);
const links = allDocsYaml.nodes.map(({ items, title }) => {
return { title, items: items.filter((t) => t !== 'Todo') };
});
const links = allDocMap.nodes.reduce((agg, { items }) => {
items.forEach((item) => {
if (item.name !== 'Todo') {
if (agg[item.group]) {
agg[item.group].push(item);
} else {
agg[item.group] = [item];
}
}
});
return agg;
}, {});

return (
<Stack direction="vertical" gap="2rem">
{links.map((link) => {
{Object.keys(links).map((group) => {
return (
<div>
<MenuHeading>{link.title}</MenuHeading>
<MenuHeading>{group}</MenuHeading>
<Stack direction="vertical" gap="1rem">
{link.items.map((title) => (
{links[group].map((item) => (
<MenuItem>
<Link
to={`${titleToURLPrefix[link.title]}${linkMap[title].slug}`}
>
{title}
</Link>
<Link to={`/${item.slug}`}>{item.name}</Link>
</MenuItem>
))}
</Stack>
Expand All @@ -78,8 +66,3 @@ export const Sidebar = () => {
</Stack>
);
};
const titleToURLPrefix = {
'Getting Started': '/docs/',
Packages: '/packages/',
Miscellaneous: '/miscellaneous/',
};

1 comment on commit 002e3f5

@vercel
Copy link

@vercel vercel bot commented on 002e3f5 Jul 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.