Skip to content

Commit

Permalink
Merge pull request #55 from philipp-winterle/esm-rework
Browse files Browse the repository at this point in the history
BREAKING: ESM module only
BREAKING: nodejs 18+
  • Loading branch information
philipp-winterle authored Jun 17, 2024
2 parents 0786481 + 0c3b896 commit 5ac681e
Show file tree
Hide file tree
Showing 36 changed files with 11,749 additions and 3,651 deletions.
7 changes: 4 additions & 3 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"ecmaVersion": 12,
"sourceType": "script"
},
"plugins": ["@babel"],
"plugins": ["@babel", "sort-destructure-keys"],
"rules": {
"accessor-pairs": "error",
"array-bracket-newline": "error",
Expand Down Expand Up @@ -225,7 +225,6 @@
"semi-spacing": "error",
"semi-style": "error",
"sort-imports": "off",
"sort-keys": "error",
"sort-vars": "error",
"space-before-blocks": "error",
"space-before-function-paren": "off",
Expand All @@ -244,6 +243,8 @@
"wrap-iife": "error",
"wrap-regex": "error",
"yield-star-spacing": "error",
"yoda": "error"
"yoda": "error",
"sort-keys": ["error", "asc", { "caseSensitive": true, "natural": true, "minKeys": 5 }],
"sort-destructure-keys/sort-destructure-keys": ["warn", { "caseSensitive": true }]
}
}
2 changes: 1 addition & 1 deletion .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:

strategy:
matrix:
node-version: [16.x, 18.x, 20.x]
node-version: [18.x, 20.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 16
node-version: 20
- run: yarn
- run: yarn test

Expand All @@ -25,7 +25,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 16
node-version: 20
registry-url: https://registry.npmjs.org/
- run: yarn
- run: yarn publish
Expand Down
21 changes: 21 additions & 0 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Versioning and Tagging

on:
push:
branches:
- main

permissions:
contents: write
pull-requests: write

jobs:
release-please:
runs-on: ubuntu-latest
steps:
- uses: googleapis/release-please-action@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
# this is a built-in strategy in release-please, see "Action Inputs"
# for more options
release-type: simple
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ tmp/*
yarn-error.log
test.js
.vscode
test/screenshots
test/results/*
!test/results/.gitkeep
test/*.css
3 changes: 3 additions & 0 deletions .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh
echo "Commit Linting - Please follow the commit message format of conventional-commits!"
commitlint --edit $1
4 changes: 0 additions & 4 deletions .husky/pre-commit

This file was deleted.

2 changes: 2 additions & 0 deletions .husky/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
npm test
42 changes: 21 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
#### Feature Facts

- Amazing speed
- Designed to be used by power users as a nodejs module (no useless browser usage)
- :boom: **Only library which is able to extract summarized critical css from multiple urls which has a common use case -> Most of the websites using one css file for multiple subpages** :boom: :metal:
- When using multiple urls a max concurrency of extraction is adjustable. For machines with less power
- Ongoing maintenance because of being used in enterprise environment
- Returns not only the critical css. Also returns the remaining css of your given file. You don't need to include the full css on your page or reduce the css on your own :heart:
- Amazing speed
- Designed to be used by power users as a nodejs module (no useless browser usage)
- :boom: **Only library which is able to extract summarized critical css from multiple urls which has a common use case -> Most of the websites using one css file for multiple subpages** :boom: :metal:
- When using multiple urls a max concurrency of extraction is adjustable. For machines with less power
- Ongoing maintenance because of being used in enterprise environment
- Returns not only the critical css. Also returns the remaining css of your given file. You don't need to include the full css on your page or reduce the css on your own :heart:

## Performance

Expand All @@ -33,10 +33,10 @@ There are some other libraries out there dealing with the topic of extracting th

### Requirements

- minimum nodejs > 12 | recommended nodejs 16+
- async/await
- Promises
- puppeteer dependecies on UNIX bases OS (including MacOSX)
- minimum nodejs > 12 | recommended nodejs 16+
- async/await
- Promises
- puppeteer dependecies on UNIX bases OS (including MacOSX)

> Due to some dependencies of crittr you may need to install some additional software.
> Puppeteer has some special requirements if you are running on an UNIX based operation system. You can read more about this fact here. Including a list of what to install: [Puppeteer Troubleshooting](https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md#chrome-headless-doesnt-launch)
Expand All @@ -45,7 +45,7 @@ There are some other libraries out there dealing with the topic of extracting th

To use crittr as a module or cli in your nodejs environment just install it with

```
```shell
npm i crittr
```

Expand Down Expand Up @@ -166,7 +166,7 @@ Crittr({

You can see the output of the time measurement after every run. So you will be able to check you overall processing time.

```
```shell
▶ Crittr Run Initialized timer...
◼ Crittr Run Timer run for: 2.33s
```
Expand Down Expand Up @@ -253,20 +253,20 @@ This keepSelectors options will match every selector that begins with `.test` an

## FAQ :confused:

- Why do I need to put my css file in when I only want to extract the critical css?
- Why do I need to put my css file in when I only want to extract the critical css?
You don't need to but if you don't set your css file as an option you may not receive all vendor prefixes you may expect. This is due testing with only one browser engine which drop other prefixes.
- After including the remaining css aswell my page starts looking different. Why is that?
- After including the remaining css aswell my page starts looking different. Why is that?
If you progress more than 1 url at the same time crittr can not determinate where a rule has to be positioned in the whole css to not get in conflict with other rules overwriting them. You have to write clean css to prevent such an behaviour. Overwriting rules should always have longer selectors than the rules they are overwriting to raise priority.

## Upcoming :trumpet:

- [ ] :star: cookie includes
- [x] :star: wildcards
- [x] :+1: compress output option
- [x] :fire: return of the remaining css aswell
- [x] :grey_question: multi selector partial matches
- [x] :tea: returning of remaining css aswell (optional)
- [x] :clock2: performance boost for large css
- [ ] :star: cookie includes
- [x] :star: wildcards
- [x] :+1: compress output option
- [x] :fire: return of the remaining css aswell
- [x] :grey_question: multi selector partial matches
- [x] :tea: returning of remaining css aswell (optional)
- [x] :clock2: performance boost for large css

## Known Bugs :shit:

Expand Down
1 change: 1 addition & 0 deletions commitlint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default {extends: ['@commitlint/config-conventional']};
40 changes: 16 additions & 24 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,34 @@
'use strict';
global.crittr_project_path = __dirname;

const log = require('signale');
const path = require('path');
import { createRequire } from 'node:module';
import log from '@dynamicabot/signales';
import path from 'path';
import url from 'url';
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
const NODE_ENV = process.env.NODE_ENV || 'production';

let IS_NPM_PACKAGE = false;
try {
const require = createRequire(import.meta.url);
IS_NPM_PACKAGE = !!require.resolve('crittr');
} catch (e) {}

const pathToCrittr = NODE_ENV === 'development' && !IS_NPM_PACKAGE ? 'lib' : 'lib'; // Only keep for later browser support?
const Crittr = require(path.join(__dirname, pathToCrittr, 'classes', 'Crittr.class.js'));

/**
*
* @param options
* @returns {Promise<[<string>, <string>]>}
*/
module.exports = options => {
return new Promise(async (resolve, reject) => {
log.time('Crittr Run');
export default async options => {
log.time('Crittr Run');
const { Crittr } = await import(path.join(__dirname, pathToCrittr, 'classes', 'Crittr.class.js'));

let crittr;
let resultObj = { critical: null, rest: null };

let crittr;
let resultObj = { critical: null, rest: null };
crittr = new Crittr(options);

try {
crittr = new Crittr(options);
} catch (err) {
reject(err);
}
resultObj = await crittr.run();

try {
resultObj = await crittr.run();
} catch (err) {
reject(err);
}
resolve(resultObj);
log.timeEnd('Crittr Run');
});
log.timeEnd('Crittr Run');
return resultObj;
};
9 changes: 5 additions & 4 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
// jest.config.js
module.exports = {
export default {
projects: [
{
displayName: 'Basic',
globalSetup: './test/setup.cjs',
globalTeardown: './test/teardown.cjs',
globalSetup: './test/setup.js',
globalTeardown: './test/teardown.js',
roots: ['<rootDir>'],
testMatch: ['**/test/tests/**/*.test.cjs?(x)'],
testMatch: ['**/test/tests/**/*.test.js?(x)'],
testEnvironmentOptions: {
url: 'http://localhost',
},
},
],
transform: {},
};
12 changes: 8 additions & 4 deletions lib/Constants.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
const path = require('path');
import path from 'path';
import { createRequire } from 'module';
import url from 'url';
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
const require = createRequire(import.meta.url);
const package_json = require(path.join('..', 'package.json'));

module.exports = {
export default {
// DEFAULTS
PROJECT_DIR: path.resolve('..'),
PROJECT_DIR: path.resolve(__dirname, '..'),

// CRITTR BASED

PRINT_BROWSER_CONSOLE: false,
DROP_KEYFRAMES: true,
PUPPETEER_HEADLESS: "new",
PUPPETEER_HEADLESS: 'new',
BROWSER_USER_AGENT: 'Crittr ' + package_json.version,
BROWSER_CACHE_ENABLED: true,
BROWSER_JS_ENABLED: true,
Expand Down
12 changes: 5 additions & 7 deletions lib/classes/Ast.class.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
const _ = require('lodash');
const log = require('signale');
const CONSTANTS = require('../Constants');
const Rule = require('./Rule.class');
const hash = require('object-hash');
import _ from 'lodash';
import Rule from './Rule.class.js';
import hash from 'object-hash';

// PRIVATE VARS
const REMOVEABLE_PROPS = ['position'];
Expand Down Expand Up @@ -120,7 +118,7 @@ class Ast {
break;
}

if(rulesObj[0].rule.type === 'rule' && !rulesObj[0].rule.hasOwnProperty('declarations')) {
if (rulesObj[0].rule.type === 'rule' && !rulesObj[0].rule.hasOwnProperty('declarations')) {
break;
}

Expand Down Expand Up @@ -151,4 +149,4 @@ Ast.TYPES_TO_REMOVE = ['comment'];

Ast.MEDIA_PREFIX = '@media ';

module.exports = Ast;
export default Ast;
50 changes: 24 additions & 26 deletions lib/classes/Crittr.class.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
'use strict';

const fs = require('fs-extra');
const util = require('util');
const path = require('path');
import fs from 'fs-extra';
import util from 'util';
import path from 'path';
import doDebug from 'debug';
import log from '@dynamicabot/signales';
import chalk from 'chalk';
import merge from 'deepmerge';
import { isPlainObject } from 'is-plain-object';
import Queue from 'run-queue';
import puppeteer from 'puppeteer-extra';
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
import CleanCSS from 'clean-css';
import postcss from 'postcss';
import sortMediaQueries from 'postcss-sort-media-queries';
import DEFAULTS from '../Constants.js';
import Ast from './Ast.class.js';
import CssTransformator from './CssTransformator.class.js';
import extractCriticalCss_script from '../evaluation/extract_critical_with_css.js';

const debug = doDebug('crittr:Crittr.class');
const readFilePromise = util.promisify(fs.readFile);
const debug = require('debug')('Crittr Class');
const log = require('signale');
const chalk = require('chalk');
const merge = require('deepmerge');
const { isPlainObject } = require('is-plain-object');
const Queue = require('run-queue');
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth')
puppeteer.use(StealthPlugin())
const devices = puppeteer.devices;
const CleanCSS = require('clean-css');
const postcss = require('postcss');
const sortMediaQueries = require('postcss-sort-media-queries');

const DEFAULTS = require('../Constants');
const Ast = require('./Ast.class');

const CssTransformator = require('./CssTransformator.class');
const extractCriticalCss_script = require('../evaluation/extract_critical_with_css');
puppeteer.use(StealthPlugin());

/**
* CRITTR Class
Expand Down Expand Up @@ -711,7 +709,7 @@ class Crittr {
url = url.substring(0, url.indexOf('#'));
}

const htmlContent = await fs.readFile(path.join(global.crittr_project_path, url), 'utf8');
const htmlContent = await fs.readFile(path.join(DEFAULTS.PROJECT_DIR, url), 'utf8');
await page.setContent(htmlContent);
} else {
await page.goto(url, {
Expand All @@ -730,7 +728,7 @@ class Crittr {
if (hasError === false) {
try {
debug('evaluateUrl - Extracting critical selectors');
await page.waitForTimeout(250); // Needed because puppeteer sometimes isn't able to handle quick tab openings
await new Promise(r => setTimeout(r, 250));
if (this.options.takeScreenshots === true) {
let screenName = url.replace(/[^\w\s]/gi, '_') + '.png';
if (typeof this.options.screenshotNameGenerator === 'function') {
Expand Down Expand Up @@ -807,4 +805,4 @@ class Crittr {
}
}

module.exports = Crittr;
export { Crittr, Crittr as default };
Loading

0 comments on commit 5ac681e

Please sign in to comment.