Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(webpack): replace file system cache with in-memory cache (fixes #878) #879

Merged
merged 3 commits into from Dec 1, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 0 additions & 9 deletions docs/BUNDLERS_INTEGRATION.md
Expand Up @@ -177,14 +177,6 @@ The loader accepts the following options:

Setting this option to `true` will include source maps for the generated CSS so that you can see where source of the class name in devtools. We recommend to enable this only in development mode because the sourcemap is inlined into the CSS files.

- `cacheDirectory: string` (default: `'.linaria-cache'`):

Path to the directory where the loader will output the intermediate CSS files. You can pass a relative or absolute directory path. Make sure the directory is inside the working directory for things to work properly. **You should add this directory to `.gitignore` so you don't accidentally commit them.**

- `extension: string` (default: `'.linaria.css'`):

An extension of the intermediate CSS files.

- `preprocessor: 'none' | 'stylis' | Function` (default: `'stylis'`)

You can override the pre-processor if you want to override how the loader processes the CSS.
Expand Down Expand Up @@ -218,7 +210,6 @@ You can pass options to the loader like so:
loader: '@linaria/webpack-loader',
options: {
sourceMap: false,
cacheDirectory: '.linaria-cache',
},
}
```
Expand Down
7 changes: 1 addition & 6 deletions packages/webpack4-loader/package.json
Expand Up @@ -38,22 +38,17 @@
"watch": "yarn build --watch"
},
"devDependencies": {
"@types/cosmiconfig": "^5.0.3",
"@types/enhanced-resolve": "^3.0.6",
"@types/loader-utils": "^1.1.3",
"@types/mkdirp": "^0.5.2",
"@types/normalize-path": "^3.0.0",
"source-map": "^0.7.3"
},
"dependencies": {
"@linaria/babel-preset": "^3.0.0-beta.15",
"@linaria/logger": "^3.0.0-beta.15",
"cosmiconfig": "^5.1.0",
"enhanced-resolve": "^4.1.0",
"find-yarn-workspace-root": "^1.2.1",
"loader-utils": "^1.2.3",
"mkdirp": "^0.5.1",
"normalize-path": "^3.0.0"
"mkdirp": "^0.5.1"
},
"peerDependencies": {
"@babel/core": ">=7"
Expand Down
55 changes: 7 additions & 48 deletions packages/webpack4-loader/src/index.ts
Expand Up @@ -4,24 +4,13 @@
* returns transformed code without template literals and attaches generated source maps
*/

import fs from 'fs';
import path from 'path';
import mkdirp from 'mkdirp';
import normalize from 'normalize-path';
import loaderUtils from 'loader-utils';
import enhancedResolve from 'enhanced-resolve';
import findYarnWorkspaceRoot from 'find-yarn-workspace-root';
import type { RawSourceMap } from 'source-map';
import cosmiconfig from 'cosmiconfig';
import { EvalCache, Module, transform } from '@linaria/babel-preset';
import { debug, notify } from '@linaria/logger';

const workspaceRoot = findYarnWorkspaceRoot();
const lernaConfig = cosmiconfig('lerna', {
searchPlaces: ['lerna.json'],
}).searchSync();
const lernaRoot =
lernaConfig !== null ? path.dirname(lernaConfig.filepath) : null;
import { addFile } from './outputCssLoader';

type LoaderContext = Parameters<typeof loaderUtils.getOptions>[0];

Expand All @@ -35,6 +24,8 @@ const castSourceMap = <T extends { version: number } | { version: string }>(
}
: undefined;

const outputCssLoader = require.resolve('./outputCssLoader');

export default function webpack4Loader(
this: LoaderContext,
content: string,
Expand All @@ -51,28 +42,11 @@ export default function webpack4Loader(

const {
sourceMap = undefined,
cacheDirectory = '.linaria-cache',
preprocessor = undefined,
extension = '.linaria.css',
resolveOptions = {},
...rest
} = loaderUtils.getOptions(this) || {};

const root = workspaceRoot || lernaRoot || process.cwd();

const baseOutputFileName = this.resourcePath.replace(/\.[^.]+$/, extension);

const outputFilename = normalize(
path.join(
path.isAbsolute(cacheDirectory)
? cacheDirectory
: path.join(process.cwd(), cacheDirectory),
this.resourcePath.includes(root)
? path.relative(root, baseOutputFileName)
: baseOutputFileName
)
);

// this._compilation is a deprecated API
// However there seems to be no other way to access webpack's resolver
// There is this.resolve, but it's asynchronous
Expand Down Expand Up @@ -130,7 +104,6 @@ export default function webpack4Loader(
result = transform(content, {
filename: path.relative(process.cwd(), this.resourcePath),
inputSourceMap: inputSourceMap ?? undefined,
outputFilename,
pluginOptions: rest,
preprocessor,
});
Expand Down Expand Up @@ -161,28 +134,14 @@ export default function webpack4Loader(
});
}

// Read the file first to compare the content
// Write the new content only if it's changed
// This will prevent unnecessary WDS reloads
let currentCssText;

try {
currentCssText = fs.readFileSync(outputFilename, 'utf-8');
} catch (e) {
// Ignore error
}
addFile(this.resourcePath, cssText);

if (currentCssText !== cssText) {
mkdirp.sync(path.dirname(outputFilename));
fs.writeFileSync(outputFilename, cssText);
}
const request = `linaria.css!=!${outputCssLoader}!${this.resourcePath}`;
Anber marked this conversation as resolved.
Show resolved Hide resolved
const stringifiedRequest = loaderUtils.stringifyRequest(this, request);

this.callback(
null,
`${result.code}\n\nrequire(${loaderUtils.stringifyRequest(
this,
outputFilename
)});`,
`${result.code}\n\nrequire(${stringifiedRequest});`,
castSourceMap(result.sourceMap)
);
return;
Expand Down
9 changes: 9 additions & 0 deletions packages/webpack4-loader/src/outputCssLoader.ts
@@ -0,0 +1,9 @@
const cssLookup = new Map<string, string>();

export const addFile = (id: string, content: string) => {
cssLookup.set(id, content);
};

export default async function outputCssLoader(this: { resourcePath: string }) {
Anber marked this conversation as resolved.
Show resolved Hide resolved
return cssLookup.get(this.resourcePath) ?? '';
}
7 changes: 1 addition & 6 deletions packages/webpack5-loader/package.json
Expand Up @@ -38,23 +38,18 @@
"watch": "yarn build --watch"
},
"devDependencies": {
"@types/cosmiconfig": "^5.0.3",
"@types/enhanced-resolve": "^3.0.6",
"@types/loader-utils": "^1.1.3",
"@types/mkdirp": "^0.5.2",
"@types/normalize-path": "^3.0.0",
"source-map": "^0.7.3",
"webpack": "^5.6.0"
},
"dependencies": {
"@linaria/babel-preset": "^3.0.0-beta.15",
"@linaria/logger": "^3.0.0-beta.15",
"cosmiconfig": "^5.1.0",
"enhanced-resolve": "^5.3.1",
"find-yarn-workspace-root": "^1.2.1",
"loader-utils": "^2.0.0",
"mkdirp": "^0.5.1",
"normalize-path": "^3.0.0"
"mkdirp": "^0.5.1"
},
"peerDependencies": {
"@babel/core": ">=7",
Expand Down
53 changes: 6 additions & 47 deletions packages/webpack5-loader/src/index.ts
Expand Up @@ -4,24 +4,15 @@
* returns transformed code without template literals and attaches generated source maps
*/

import fs from 'fs';
import path from 'path';
import loaderUtils from 'loader-utils';
import mkdirp from 'mkdirp';
import normalize from 'normalize-path';
import enhancedResolve from 'enhanced-resolve';
import findYarnWorkspaceRoot from 'find-yarn-workspace-root';
import type { RawSourceMap } from 'source-map';
import cosmiconfig from 'cosmiconfig';
import { EvalCache, Module, transform } from '@linaria/babel-preset';
import { debug, notify } from '@linaria/logger';
import { addFile } from './outputCssLoader';

const workspaceRoot = findYarnWorkspaceRoot();
const lernaConfig = cosmiconfig('lerna', {
searchPlaces: ['lerna.json'],
}).searchSync();
const lernaRoot =
lernaConfig !== null ? path.dirname(lernaConfig.filepath) : null;
const outputCssLoader = require.resolve('./outputCssLoader');

export default function webpack5Loader(
this: any,
Expand All @@ -39,28 +30,11 @@ export default function webpack5Loader(

const {
sourceMap = undefined,
cacheDirectory = '.linaria-cache',
preprocessor = undefined,
extension = '.linaria.css',
resolveOptions = {},
...rest
} = this.getOptions() || {};

const root = workspaceRoot || lernaRoot || process.cwd();

const baseOutputFileName = this.resourcePath.replace(/\.[^.]+$/, extension);

const outputFilename = normalize(
path.join(
path.isAbsolute(cacheDirectory)
? cacheDirectory
: path.join(process.cwd(), cacheDirectory),
this.resourcePath.includes(root)
? path.relative(root, baseOutputFileName)
: baseOutputFileName
)
);

// this._compilation is a deprecated API
// However there seems to be no other way to access webpack's resolver
// There is this.resolve, but it's asynchronous
Expand Down Expand Up @@ -123,7 +97,6 @@ export default function webpack5Loader(
result = transform(content, {
filename: path.relative(process.cwd(), this.resourcePath),
inputSourceMap: inputSourceMap ?? undefined,
outputFilename,
pluginOptions: rest,
preprocessor,
});
Expand Down Expand Up @@ -154,28 +127,14 @@ export default function webpack5Loader(
});
}

// Read the file first to compare the content
// Write the new content only if it's changed
// This will prevent unnecessary WDS reloads
let currentCssText;
addFile(this.resourcePath, cssText);

try {
currentCssText = fs.readFileSync(outputFilename, 'utf-8');
} catch (e) {
// Ignore error
}

if (currentCssText !== cssText) {
mkdirp.sync(path.dirname(outputFilename));
fs.writeFileSync(outputFilename, cssText);
}
const request = `linaria.css!=!${outputCssLoader}!${this.resourcePath}`;
const stringifiedRequest = loaderUtils.stringifyRequest(this, request);

this.callback(
null,
`${result.code}\n\nrequire(${loaderUtils.stringifyRequest(
this,
outputFilename
)});`,
`${result.code}\n\nrequire(${stringifiedRequest});`,
result.sourceMap ?? undefined
);
return;
Expand Down
9 changes: 9 additions & 0 deletions packages/webpack5-loader/src/outputCssLoader.ts
@@ -0,0 +1,9 @@
const cssLookup = new Map<string, string>();

export const addFile = (id: string, content: string) => {
cssLookup.set(id, content);
};

export default async function outputCssLoader(this: { resourcePath: string }) {
return cssLookup.get(this.resourcePath) ?? '';
}
10 changes: 1 addition & 9 deletions yarn.lock
Expand Up @@ -6760,14 +6760,6 @@ find-up@^4.0.0, find-up@^4.1.0:
locate-path "^5.0.0"
path-exists "^4.0.0"

find-yarn-workspace-root@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-1.2.1.tgz#40eb8e6e7c2502ddfaa2577c176f221422f860db"
integrity sha512-dVtfb0WuQG+8Ag2uWkbG79hOUzEsRrhBzgfn86g2sJPkzmcpGdghbNTfUKGTxymFrY/tLIodDzLoW9nOJ4FY8Q==
dependencies:
fs-extra "^4.0.3"
micromatch "^3.1.4"

findup-sync@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1"
Expand Down Expand Up @@ -6878,7 +6870,7 @@ fs-constants@^1.0.0:
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==

fs-extra@^4.0.2, fs-extra@^4.0.3:
fs-extra@^4.0.2:
version "4.0.3"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94"
integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==
Expand Down