Skip to content

Commit

Permalink
feat: 支持 append 自定义内容到编译结果中 #4
Browse files Browse the repository at this point in the history
  • Loading branch information
meixg committed Sep 10, 2021
1 parent 3f3b25c commit a371d37
Show file tree
Hide file tree
Showing 9 changed files with 219 additions and 126 deletions.
12 changes: 12 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"args": [
"index.test.ts"
],
"name": "jest task",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"request": "launch",
"skipFiles": [
"<node_internals>/**"
],
"type": "pwa-node"
},
{
"name": "Launch Program",
"program": "${file}",
Expand Down
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,51 @@ export default {
npm run test
```

## 自定义样式输出格式

san-ssr 本身不负责样式的处理。本插件通过封装 san-ssr 产物(render 函数)的形式处理样式产物:

```javascript
if (css) {
code += 'const originSanSSRRenders = module.exports.sanSSRRenders;\n';
code += 'Object.keys(originSanSSRRenders).forEach(renderName => {\n';
code += ' originSanSSRRenders[renderName] = makeRender(originSanSSRRenders[renderName]);\n';
code += '});\n';
code += 'module.exports = Object.assign(sanSSRResolver.getRenderer({id: "default"}), exports)';
code += 'function makeRender(originRender) {\n';
code += ' return function (data, ...params) {\n';
code += ' if (global.__COMPONENT_CONTEXT__) {\n';
code += ` global.__COMPONENT_CONTEXT__[${styleId}] = ${JSON.stringify(css)};\n`;
code += ' }\n';
if (Object.keys(locals).length > 0) {
code += ' data[\'$style\'] = {\n';
code += ` ${Object.keys(locals).map(item =>
`${JSON.stringify(item)}: ${JSON.stringify(locals[item])}`
).join(',')}\n`;
code += ' };\n';
}
code += ' return originRender(data, ...params);\n';
code += ' };\n';
code += '}\n';
}
```

这段代码会添加在产物的最后,作为输出。

如果该内容不能满足要求,使用者可通过 `appendRenderFunction` 选项自行设置该内容:

```javascript
plugins: [
new SanSsrPlugin({
appendRenderFunction(styleId: string, css: string = '', locals: Record<string, string>) {
return ``;
}
})
]
```

参数的具体内容可参考上方默认的输出。

<!-- ## Options
## 实现原理
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 10 additions & 2 deletions src/lib/callSanSsr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,15 @@ export function callSanSsr(
context: string,
sanSsrOptions: sanSsrOptions,
reportError: (err: Error) => void,
tsConfigPath?: string
options?: {
tsConfigPath?: string;
appendRenderFunction?: typeof makeCustomRenderFunction;
}
) {
const {
tsConfigPath,
appendRenderFunction = makeCustomRenderFunction
} = options || {};
if (!tsFile.content) {
reportError(new Error('Ts code must be specified'));
return;
Expand All @@ -45,7 +52,7 @@ export function callSanSsr(
tsFile.path).replace(/\\/g, '/'
);
const styleId = JSON.stringify(hash(relPath));
jsCode += makeCustomRenderFunction(
jsCode += appendRenderFunction(
styleId,
stylesRes?.cssCode,
stylesRes?.locals || {}
Expand Down Expand Up @@ -110,6 +117,7 @@ function makeCustomRenderFunction(
code += 'Object.keys(originSanSSRRenders).forEach(renderName => {\n';
code += ' originSanSSRRenders[renderName] = makeRender(originSanSSRRenders[renderName]);\n';
code += '});\n';
code += 'module.exports = Object.assign(sanSSRResolver.getRenderer({id: "default"}), exports)';
code += 'function makeRender(originRender) {\n';
code += ' return function (data, ...params) {\n';
code += ' if (global.__COMPONENT_CONTEXT__) {\n';
Expand Down
10 changes: 8 additions & 2 deletions src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const {
} = fsPromise;

const id = 'san-ssr-loader';
interface PluginOptions {
export interface PluginOptions {
/**
* 运行时代码
*/
Expand Down Expand Up @@ -43,6 +43,7 @@ interface PluginOptions {
*/
path: string;
} & sanSsrOptions;
appendRenderFunction?: (styleId: string, css?: string, locals?: Record<string, string>) => string;
}

export default class SanSSRLoaderPlugin {
Expand All @@ -51,11 +52,13 @@ export default class SanSSRLoaderPlugin {
sanSsrOptions: sanSsrOptions;
initialized: boolean;
tsConfigPath?: string;
appendRenderFunction?: PluginOptions['appendRenderFunction'];
constructor(options?: PluginOptions) {
this.runtimeHelperOutput = options?.runtimeHelper?.output || 'runtimeHelpers';
this.outputPath = options?.output?.path || '';
this.sanSsrOptions = options?.output || {};
this.tsConfigPath = options?.tsConfigPath;
this.appendRenderFunction = options?.appendRenderFunction;
this.initialized = false;
}
apply(compiler: Compiler) {
Expand Down Expand Up @@ -110,7 +113,10 @@ export default class SanSSRLoaderPlugin {
...this.sanSsrOptions,
},
reportError,
this.tsConfigPath
{
tsConfigPath: this.tsConfigPath,
appendRenderFunction: this.appendRenderFunction
}
);

if (jsRes) {
Expand Down
4 changes: 4 additions & 0 deletions src/san-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ export default function (this: loader.LoaderContext, content: string) {
const callback = this.async();
const done = callback ? () => callback(null, content) : noop;

if (this.resourceQuery && this.resourceQuery.includes('lang=')) {
return done();
}

const templateRequireCalls = extractRequire(content)
.filter(req => req.includes('type=template'));

Expand Down
17 changes: 13 additions & 4 deletions test/helpers/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,34 @@ import path from 'path';
import webpack from 'webpack';
import {createFsFromVolume, Volume} from 'memfs';
import {getConfig} from './webpack.config';
import {PluginOptions} from '../../src/plugin';

export function compiler(fixture: string): Promise<webpack.Stats> {
const config = getConfig(fixture);
export function compiler(fixture: string, options: Partial<PluginOptions> = {}): Promise<{
stats: webpack.Stats;
outputContent: string;
}> {
const config = getConfig(fixture, options);
const compiler = webpack(config);

const fileSys = createFsFromVolume(new Volume());

// @ts-ignore
compiler.outputFileSystem = createFsFromVolume(new Volume());
compiler.outputFileSystem = fileSys;
compiler.outputFileSystem.join = path.join.bind(path);

return new Promise((resolve, reject) => {
compiler.run((err, stats) => {
if (err) {
reject(err);
return;
}
if (stats.hasErrors()) {
reject(new Error(stats.toJson().errors.join('\n')));
return;
}

resolve(stats);
const outputContent = fileSys.readFileSync('./test/helpers/php/test/samples/index.js', 'utf-8') as string;
resolve({stats, outputContent});
});
});
};
Loading

0 comments on commit a371d37

Please sign in to comment.