Skip to content

Commit

Permalink
Fix source map behaviour in Parcel and move node_modules compiled ext…
Browse files Browse the repository at this point in the history
…raction to new parcel transformer (#1631)

* Move node_modules compiled extraction to new parcel transformer

* Add changeset

* Remove polyfill from test snapshot

* Update syntax to remove sketchy null checks

* Update readme
  • Loading branch information
JakeLane authored Mar 6, 2024
1 parent ac82deb commit 0666530
Show file tree
Hide file tree
Showing 25 changed files with 462 additions and 58 deletions.
7 changes: 7 additions & 0 deletions .changeset/lovely-apes-train.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@compiled/parcel-transformer-external': minor
'@compiled/parcel-transformer': minor
'@compiled/parcel-config': minor
---

Add new parcel transformer for distributed Compiled code
2 changes: 2 additions & 0 deletions examples/parcel/.parcelrc
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
"transformers": {
"*.{js,mjs,jsx,cjs,ts,tsx}": [
// Manually remove the babel transformer so we don't use the root babel config
"@compiled/parcel-transformer-external",
"@compiled/parcel-transformer",
"@parcel/transformer-js",
"@parcel/transformer-react-refresh-wrap"
],
"*.customjsx": [
"@compiled/parcel-transformer-external",
"@compiled/parcel-transformer",
"@parcel/transformer-js",
"@parcel/transformer-react-refresh-wrap",
Expand Down
1 change: 1 addition & 0 deletions examples/parcel/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@babel/plugin-proposal-decorators": "^7.22.15",
"@compiled/parcel-config": "*",
"@compiled/parcel-transformer": "*",
"@compiled/parcel-transformer-external": "*",
"@parcel/config-default": "^2.8.3",
"@parcel/optimizer-htmlnano": "^2.8.3",
"@parcel/packager-html": "^2.8.3",
Expand Down
6 changes: 5 additions & 1 deletion fixtures/parcel-transformer-test-app/.parcelrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"extends": "@parcel/config-default",
"transformers": {
"*.{js,jsx}": ["@compiled/parcel-transformer", "..."]
"*.{js,jsx}": [
"@compiled/parcel-transformer-external",
"@compiled/parcel-transformer",
"..."
]
}
}
10 changes: 8 additions & 2 deletions fixtures/parcel-transformer-test-app/src/index.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import '@compiled/react';
console.log('File START');

import { css } from '@compiled/react';

const styles = css({ backgroundColor: 'green' });

const App = () => (
<>
<div css={{ fontSize: 50, color: 'red' }}>hello from parcel</div>
<div css={[{ fontSize: 50, color: 'red' }, styles]}>hello from parcel</div>
</>
);

console.log('File END');
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
{
"extends": "@parcel/config-default",
"transformers": {
"*.{js,jsx}": ["@compiled/parcel-transformer", "..."]
"*.{js,jsx}": [
"@compiled/parcel-transformer-external",
"@compiled/parcel-transformer",
"..."
]
},
"optimizers": {
"*.html": ["@compiled/parcel-optimizer", "..."]
"*.html": [
"@compiled/parcel-optimizer",
"..."
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
},
"devDependencies": {
"@compiled/parcel-transformer": "*",
"@compiled/parcel-transformer-external": "*",
"@parcel/config-default": "^2.8.3"
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"extends": "@parcel/config-default",
"transformers": {
"*.{js,jsx}": ["@compiled/parcel-transformer", "..."]
"*.{js,jsx}": [
"@compiled/parcel-transformer-external",
"@compiled/parcel-transformer",
"..."
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
},
"devDependencies": {
"@compiled/parcel-transformer": "*",
"@compiled/parcel-transformer-external": "*",
"@parcel/config-default": "^2.8.3"
}
}
11 changes: 9 additions & 2 deletions fixtures/parcel-transformer-test-extract-app/.parcelrc
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
{
"extends": "@parcel/config-default",
"transformers": {
"*.{js,jsx}": ["@compiled/parcel-transformer", "..."]
"*.{js,jsx}": [
"@compiled/parcel-transformer-external",
"@compiled/parcel-transformer",
"..."
]
},
"optimizers": {
"*.html": ["@compiled/parcel-optimizer", "..."]
"*.html": [
"@compiled/parcel-optimizer",
"..."
]
}
}
1 change: 1 addition & 0 deletions fixtures/parcel-transformer-test-extract-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"@compiled/babel-component-extracted-fixture": "*",
"@compiled/babel-component-fixture": "*",
"@compiled/parcel-transformer": "*",
"@compiled/parcel-transformer-external": "*",
"@parcel/config-default": "^2.8.3"
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"test": "jest --no-cache",
"test:cover": "yarn test --collectCoverage",
"test:imports": "node test/test-imports",
"test:parcel": "jest --testMatch '**/src/**/*.parceltest.{ts,tsx}'",
"test:parcel": "jest --testMatch '**/src/**/*.parceltest.{ts,tsx}' --testEnvironment=node",
"test:vr": "yarn loki --host host.docker.internal",
"test:watch": "jest --no-cache --watch"
},
Expand Down
6 changes: 5 additions & 1 deletion packages/parcel-config/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"transformers": {
"*.{js,mjs,jsm,jsx,es6,cjs,ts,tsx}": ["@compiled/parcel-transformer", "..."]
"*.{js,mjs,jsm,jsx,es6,cjs,ts,tsx}": [
"@compiled/parcel-transformer-external",
"@compiled/parcel-transformer",
"..."
]
},
"optimizers": {
"*.html": ["@compiled/parcel-optimizer", "..."]
Expand Down
1 change: 1 addition & 0 deletions packages/parcel-config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"dependencies": {
"@compiled/parcel-optimizer": "^0.4.0",
"@compiled/parcel-transformer": "^0.14.0",
"@compiled/parcel-transformer-external": "^0.0.1",
"@parcel/plugin": "^2.8.3"
},
"devDependencies": {},
Expand Down
19 changes: 19 additions & 0 deletions packages/parcel-transformer-external/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# @compiled/parcel-transformer-external

Parcel plugin for Compiled which collects extracted styles from node_modules. This is required when `@compiled/babel-plugin-strip-runtime` is configured with `extractStylesToDirectory` which generates code like the following:

```js
require('./index.compiled.css');
```

See the [@compiled/babel-plugin-strip-runtime docs](https://compiledcssinjs.com/docs/pkg-babel-plugin-strip-runtime) for more details.

## Installation

```bash
npm i @compiled/parcel-transformer-external
```

## Usage

Detailed docs and example usage can be [found on the documentation website](https://compiledcssinjs.com/docs/pkg-parcel-transformer-external).
34 changes: 34 additions & 0 deletions packages/parcel-transformer-external/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "@compiled/parcel-transformer-external",
"version": "0.0.1",
"description": "A familiar and performant compile time CSS-in-JS library for React.",
"homepage": "https://compiledcssinjs.com/docs/pkg-parcel-transformer",
"bugs": "https://github.com/atlassian-labs/compiled/issues/new?assignees=&labels=bug&template=bug_report.md",
"repository": {
"type": "git",
"url": "https://github.com/atlassian-labs/compiled.git",
"directory": "packages/parcel-transformer-external"
},
"license": "Apache-2.0",
"author": "Michael Dougall",
"sideEffects": false,
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist",
"src"
],
"dependencies": {
"@parcel/plugin": "^2.8.3",
"@parcel/source-map": "^2.1.1"
},
"devDependencies": {
"@parcel/core": "^2.8.3",
"@parcel/fs": "^2.8.3",
"prettier": "^2.8.8"
},
"engines": {
"parcel": "^2.0.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { join } from 'path';

import Parcel, { createWorkerFarm } from '@parcel/core';
import { MemoryFS } from '@parcel/fs';
import { format } from 'prettier';

const rootPath = join(__dirname, '..', '..', '..', '..');

const workerFarm = createWorkerFarm();

afterAll(() => {
workerFarm.end();
});

const outputFS = new MemoryFS(workerFarm);

const getParcelInstance = (workingDir: string, sourceMap = false) => {
return new Parcel({
config: join(workingDir, '.parcelrc'),
entries: [join(workingDir, 'src', 'index.html')],
outputFS,
targets: {
default: {
distDir: join(workingDir, 'dist'),
sourceMap: sourceMap,
},
},
workerFarm,
mode: 'production',
});
};

it('transforms assets with compiled and extraction babel plugins', async () => {
const extractionFixtureRoot = join(rootPath, 'fixtures/parcel-transformer-test-extract-app');
const parcel = getParcelInstance(extractionFixtureRoot);
const { changedAssets, bundleGraph } = await parcel.run();

const htmlAsset = Array.from(changedAssets.values()).find(
(asset) => asset.filePath === join(extractionFixtureRoot, '/src/index.html')
);

const outputHtml = await outputFS.readFile(
bundleGraph.getBundlesWithAsset(htmlAsset!)[0].filePath,
'utf8'
);

const css = /<style>(.*?)<\/style>/.exec(outputHtml)?.pop();

if (!css) throw new Error('No CSS is found.');

expect(
format(css, {
parser: 'css',
singleQuote: true,
})
).toMatchInlineSnapshot(`
"._1wyb12am {
font-size: 50px;
}
._syaz13q2 {
color: blue;
}
._19bv1vi7 {
padding-left: 32px;
}
._19itlf8h {
border: 2px solid blue;
}
._19pk1ul9 {
margin-top: 30px;
}
._1wyb1ul9 {
font-size: 30px;
}
._bfhk1gy6 {
background-color: yellow;
}
._ca0q1vi7 {
padding-top: 32px;
}
._n3td1vi7 {
padding-bottom: 32px;
}
._u5f31vi7 {
padding-right: 32px;
}
"
`);
}, 50000);
74 changes: 74 additions & 0 deletions packages/parcel-transformer-external/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { join, dirname, isAbsolute } from 'path';

import { Transformer } from '@parcel/plugin';
import SourceMap from '@parcel/source-map';

function findTargetSourcePositions(source: string, regex: RegExp) {
const lines = source.split('\n');

const results = [];

for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const matches = line.matchAll(regex);

for (const match of matches) {
if (match && match.index != null) {
results.push({
source: match[0],
groups: match.groups,
line: i,
column: match.index,
});
}
}
}

return results;
}

export default new Transformer({
async transform({ asset, options }) {
let code = await asset.getCode();

if (code.indexOf('.compiled.css') < 0) {
// Early exit if no relevant files
return [asset];
}

let map = await asset.getMap();
for (const match of findTargetSourcePositions(
code,
/(import ['"](?<importSpec>.+\.compiled\.css)['"];)|(require\(['"](?<requireSpec>.+\.compiled\.css)['"]\);)/g
)) {
const specifierPath = match.groups?.importSpec || match.groups?.requireSpec;
if (!specifierPath) continue;

if (options.env.sourceMap) {
if (!map) map = new SourceMap(options.projectRoot);

map.offsetColumns(match.line + 1, match.column + match.source.length, -match.source.length);
}

code = code.replace(match.source, '');

const cssFilePath = isAbsolute(specifierPath)
? specifierPath
: join(dirname(asset.filePath), specifierPath);

const cssContent = (await asset.fs.readFile(cssFilePath)).toString().split('\n');
if (!asset.meta.styleRules) {
asset.meta.styleRules = [];
}
(asset.meta.styleRules as string[]).push(...cssContent);
}

asset.setCode(code);

if (map) {
asset.setMap(map);
}

return [asset];
},
});
10 changes: 10 additions & 0 deletions packages/parcel-transformer-external/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "../tsconfig.options.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist",
"module": "commonjs",
"target": "es2017"
},
"references": [{ "path": "../jest" }]
}
Loading

0 comments on commit 0666530

Please sign in to comment.