Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion e2e/fixtures/error.less.syntax-error/expect.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const assert = require("assert");

module.exports = (err) => {
assert(
err.stderr.includes(`ParseError: Unrecognised input`),
err.stderr.includes(`Unrecognised input`),
"should throw error"
);
};
14 changes: 10 additions & 4 deletions packages/mako/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,30 @@
},
"license": "MIT",
"dependencies": {
"@module-federation/webpack-bundler-runtime": "^0.8.0",
"@swc/helpers": "0.5.1",
"@types/resolve": "^1.20.6",
"chalk": "^4.1.2",
"enhanced-resolve": "^5.18.1",
"less": "^4.2.0",
"less-plugin-resolve": "^1.0.2",
"less-loader": "^12.2.0",
"loader-runner": "^4.3.0",
"loader-utils": "^3.3.1",
"lodash": "^4.17.21",
"node-libs-browser-okam": "^2.2.5",
"piscina": "^4.5.1",
"react-error-overlay": "6.0.9",
"react-refresh": "^0.14.0",
"resolve": "^1.22.8",
"sass-loader": "^16.0.5",
"semver": "^7.6.2",
"yargs-parser": "^21.1.1",
"@module-federation/webpack-bundler-runtime": "^0.8.0"
"yargs-parser": "^21.1.1"
},
"devDependencies": {
"@napi-rs/cli": "^2.18.0",
"@types/less": "^3.0.6",
"@types/loader-runner": "^2.2.8",
"@types/loader-utils": "^2.0.6",
"@types/lodash": "^4.17.1",
"@types/node": "^20.12.5",
"@types/yargs-parser": "^21.0.3",
Expand Down Expand Up @@ -90,4 +96,4 @@
"access": "public"
},
"repository": "git@github.com:umijs/mako.git"
}
}
60 changes: 17 additions & 43 deletions packages/mako/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import resolve from 'resolve';
import { type Options } from 'sass';
import * as binding from '../binding';
import { ForkTSChecker as ForkTSChecker } from './forkTSChecker';
import { LessLoaderOpts, lessLoader } from './lessLoader';
import { LessLoaderOpts, LessPlugin } from './plugins/less';
import { SassPlugin } from './plugins/sass';
import { rustPluginResolver } from './rustPlugins';
import { sassLoader } from './sassLoader';

type Config = binding.BuildParams['config'] & {
plugins?: binding.BuildParams['plugins'];
Expand Down Expand Up @@ -94,7 +94,7 @@ export async function build(params: BuildParams) {
],
];

const lessPluginAlias =
const resolveAlias =
params.config.resolve?.alias?.reduce(
(accumulator: Record<string, string>, currentValue) => {
accumulator[currentValue[0]] = currentValue[1];
Expand All @@ -104,51 +104,25 @@ export async function build(params: BuildParams) {
) || {};

// built-in less-loader
let less = lessLoader(null, {
modifyVars: params.config.less?.modifyVars || {},
globalVars: params.config.less?.globalVars,
math: params.config.less?.math,
sourceMap: params.config.less?.sourceMap || false,
plugins: [
['less-plugin-resolve', { aliases: lessPluginAlias }],
...(params.config.less?.plugins || []),
],
});
params.config.plugins.push({
name: 'less',
async load(filePath: string) {
let lessResult = await less.render(filePath);
if (lessResult) {
return lessResult;
}
},
generateEnd() {
if (!params.watch) {
less.terminate();
}
},
});
params.config.plugins.push(
new LessPlugin({
...params,
resolveAlias,
}),
);

if ((makoConfig as any)?.sass || params.config?.sass) {
const sassOpts = {
params.config.sass = {
...((makoConfig as any)?.sass || {}),
...(params.config?.sass || {}),
};
let sass = sassLoader(null, sassOpts);
params.config.plugins.push({
name: 'sass',
async load(filePath: string) {
let sassResult = await sass.render(filePath);
if (sassResult) {
return sassResult;
}
},
generateEnd() {
if (!params.watch) {
sass.terminate();
}
},
});

params.config.plugins.push(
new SassPlugin({
...params,
resolveAlias,
}),
);
}

if (makoConfig?.moduleFederation || params.config?.moduleFederation) {
Expand Down
51 changes: 0 additions & 51 deletions packages/mako/src/lessLoader/index.ts

This file was deleted.

38 changes: 0 additions & 38 deletions packages/mako/src/lessLoader/render.ts

This file was deleted.

77 changes: 77 additions & 0 deletions packages/mako/src/plugins/less/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import url from 'url';
import { BuildParams } from '../../';
import { RunLoadersOptions } from '../../runLoaders';
import { createParallelLoader } from './parallelLessLoader';

export interface LessLoaderOpts {
modifyVars?: Record<string, string>;
globalVars?: Record<string, string>;
math?:
| 'always'
| 'strict'
| 'parens-division'
| 'parens'
| 'strict-legacy'
| number;
sourceMap?: any;
/**
* A plugin can be a file path string, or a file path string with a params object.
* Notice! The file path should be a resolved path like require.resolve("less-plugin-clean-css"),
* and the params object must be a plain json. We will require the plugin file to get the plugin content.
* If the params object been accepted, that means, the required content will be treated as a factory class of Less.Plugin,
* we will create a plugin instance with the params object, or else, the required content will be treated as a plugin instance.
* We do this because the less loader runs in a worker pool for speed, and a less plugin instance can't be passed to worker directly.
*/
plugins?: (string | [string, Record<string, any>])[];
}

export class LessPlugin {
name: string;
parallelLessLoader: ReturnType<typeof createParallelLoader> | undefined;
params: BuildParams & { resolveAlias: Record<string, string> };
extOpts: RunLoadersOptions;
lessOptions: LessLoaderOpts;

constructor(params: BuildParams & { resolveAlias: Record<string, string> }) {
this.name = 'less';
this.params = params;
this.extOpts = {
alias: params.resolveAlias,
root: params.root,
};
this.lessOptions = {
modifyVars: params.config.less?.modifyVars || {},
globalVars: params.config.less?.globalVars,
math: params.config.less?.math,
sourceMap: params.config.less?.sourceMap || false,
plugins: params.config.less?.plugins || [],
};
}

load = async (filePath: string) => {
let filename = '';
try {
filename = decodeURIComponent(url.parse(filePath).pathname || '');
} catch (e) {
return;
}

if (!filename?.endsWith('.less')) {
return;
}

this.parallelLessLoader ||= createParallelLoader();
return await this.parallelLessLoader.run({
filename,
opts: this.lessOptions,
extOpts: this.extOpts,
});
};

generateEnd = () => {
if (!this.params.watch) {
this.parallelLessLoader?.destroy();
this.parallelLessLoader = undefined;
}
};
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import path from 'path';
import { Piscina } from 'piscina';
import { LessLoaderOpts } from '.';
import { RunLoadersOptions } from '../../runLoaders';

export const createParallelLoader = () =>
new Piscina<
{ filename: string; opts: LessLoaderOpts },
{ filename: string; opts: LessLoaderOpts; extOpts: RunLoadersOptions },
{ content: string; type: 'css' }
>({
filename: path.resolve(__dirname + '/render.js'),
Expand Down
61 changes: 61 additions & 0 deletions packages/mako/src/plugins/less/render.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { LessLoaderOpts } from '.';
import { RunLoadersOptions, runLoaders } from '../../runLoaders';

module.exports = async function render(param: {
filename: string;
opts: LessLoaderOpts;
extOpts: RunLoadersOptions;
}): Promise<{ content: string; type: 'css' }> {
const { modifyVars, globalVars, math, sourceMap, plugins } = param.opts;
const extOpts = param.extOpts;

const pluginInstances: Less.Plugin[] | undefined = plugins?.map((p) => {
if (Array.isArray(p)) {
const pluginModule = require(p[0]);
const PluginClass = pluginModule.default || pluginModule;
return new PluginClass(p[1]);
} else {
return require(p);
}
});

const content = await runLoaders({
alias: extOpts.alias,
root: extOpts.root,
resource: param.filename,
loaders: [
{
loader: require.resolve('less-loader'),
options: {
lessOptions: {
filename: param.filename,
javascriptEnabled: true,
math,
plugins: pluginInstances,
modifyVars,
globalVars,
rewriteUrls: 'all',
sourceMap,
},
},
},
],
})
.then((result) => {
let source: string = '';
if (result.result) {
const buf = result.result[0];
if (Buffer.isBuffer(buf)) {
source = buf.toString('utf-8');
} else {
source = buf ?? '';
}
}
return source;
})
.catch((err) => {
throw new Error(err.toString());
});

return { content: content, type: 'css' };
};
Loading
Loading