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

feat(rspack-provider): support security.checkSyntax in Rspack #3685

Merged
merged 9 commits into from
May 24, 2023
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
9 changes: 9 additions & 0 deletions .changeset/gentle-adults-move.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@modern-js/builder-rspack-provider': patch
'@modern-js/builder-shared': patch
'@modern-js/builder': patch
---

feat(rspack-provider): support security.checkSyntax in Rspack

feat(rspack-provider): 在使用 Rspack 构建时支持 security.checkSyntax 配置项
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const createDefaultConfig = () =>
output: getDefaultOutputConfig(),
tools: {},
security: {
checkSyntax: false,
nonce: '',
// sri: false
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,6 @@ export const applyDefaultPlugins = (plugins: Plugins) =>
plugins.inlineChunk(),
plugins.bundleAnalyzer(),
plugins.assetsRetry(),
plugins.checkSyntax(),
import('../plugins/fallback').then(m => m.builderPluginFallback()), // fallback should be the last plugin
]);
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
// Todo support security.sri configuration
/**
* Currently, rspack does not support the security.sri configuration.
* But it should because it's a shared configuration.
*/
// import type { SharedSecurityConfig } from '@modern-js/builder-shared';
import type {
SharedSecurityConfig,
NormalizedSharedSecurityConfig,
} from '@modern-js/builder-shared';

// export type SecurityConfig = SharedSecurityConfig;
export type SecurityConfig = SharedSecurityConfig;

// export type NormalizedSecurityConfig = Required<SecurityConfig>;

export interface SecurityConfig {
nonce?: string;
}

export type NormalizedSecurityConfig = Required<SecurityConfig>;
export type NormalizedSecurityConfig = NormalizedSharedSecurityConfig;
5 changes: 5 additions & 0 deletions packages/builder/builder-shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@
"@modern-js/types": "workspace:*",
"@modern-js/utils": "workspace:*",
"@babel/core": "^7.21.8",
"acorn": "^8.8.1",
"caniuse-lite": "^1.0.30001451",
"cheerio": "1.0.0-rc.12",
"source-map": "^0.7.4",
"webpack-sources": "^3.2.3",
"zod": "^3.20.2",
"zod-validation-error": "^0.3.0"
Expand All @@ -104,6 +108,7 @@
"@babel/preset-env": "^7.21.5",
"@scripts/vitest-config": "workspace:*",
"@types/babel__core": "^7.20.0",
"@types/caniuse-lite": "^1.0.1",
"@types/node": "^14",
"html-webpack-plugin": "5.5.0",
"terser": "^5.14.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { SyntaxError } from './type';
import chalk from '@modern-js/utils/chalk';
import { logger } from '@modern-js/builder-shared';
import { logger } from '../../../logger';

type Error = {
source: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
checkIsExcludeSource,
CheckSyntaxExclude,
} from './helpers';
import { CheckSyntaxOptions, webpack } from '../../types';
import { CheckSyntaxOptions } from '../../types';
import type { Compiler, Compilation } from 'webpack';

const HTML_REGEX = /\.html$/;
const JS_REGEX = /\.js$/;
Expand All @@ -31,14 +32,18 @@ export class CheckSyntaxPlugin {
this.ecmaVersion = getEcmaVersion(this.targets);
}

apply(complier: webpack.Compiler) {
apply(complier: Compiler) {
complier.hooks.afterEmit.tapPromise(
CheckSyntaxPlugin.name,
async (compilation: webpack.Compilation) => {
async (compilation: Compilation) => {
const outputPath = compilation.outputOptions.path || 'dist';
const emittedAssets = Array.from(compilation.emittedAssets).map(p =>
resolve(outputPath, p),
);
// not support compilation.emittedAssets in Rspack
const emittedAssets = compilation
.getAssets()
.filter(a => a.source)
.map(a => a.name)
.map(p => resolve(outputPath, p));

const files = emittedAssets.filter(
assets => HTML_REGEX.test(assets) || JS_REGEX.test(assets),
);
Expand Down
1 change: 1 addition & 0 deletions packages/builder/builder-shared/src/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export { HtmlAppIconPlugin } from './HtmlAppIconPlugin';
export { HtmlFaviconUrlPlugin, type FaviconUrls } from './HtmlFaviconUrlPlugin';
export { InlineChunkHtmlPlugin } from './InlineChunkHtmlPlugin';
export { AssetsRetryPlugin } from './AssetsRetryPlugin';
export { CheckSyntaxPlugin } from './CheckSyntaxPlugin';
11 changes: 10 additions & 1 deletion packages/builder/builder-shared/src/schema/security.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@ export const SriOptionsSchema: ZodType<SriOptions> = z.partialObj({
});

export const sharedSecurityConfigSchema = z.partialObj({
sri: z.union([SriOptionsSchema, z.boolean()]),
nonce: z.string(),
checkSyntax: z.union([
9aoy marked this conversation as resolved.
Show resolved Hide resolved
z.boolean(),
z.object({
targets: z.array(z.string()),
exclude: z.optional(
z.union([z.instanceof(RegExp), z.array(z.instanceof(RegExp))]),
),
}),
]),
});

// eslint-disable-next-line @typescript-eslint/no-unused-vars
Expand Down
1 change: 1 addition & 0 deletions packages/builder/builder-shared/src/test-stub/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ export const mockBuilderPlugins: Plugins = {
svg: genMockPlugin('builder-plugin-svg'),
html: genMockPlugin('builder-plugin-html'),
antd: genMockPlugin('antd'),
checkSyntax: genMockPlugin('builder-plugin-check-syntax'),
};
7 changes: 5 additions & 2 deletions packages/builder/builder-shared/src/types/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import type {
SharedSourceConfig,
NormalizedSharedSourceConfig,
} from './source';
import type { SharedSecurityConfig } from './security';
import type {
SharedSecurityConfig,
NormalizedSharedSecurityConfig,
} from './security';
import type {
SharedPerformanceConfig,
NormalizedSharedPerformanceConfig,
Expand Down Expand Up @@ -37,7 +40,7 @@ export type SharedNormalizedConfig = DeepReadonly<{
html: NormalizedSharedHtmlConfig;
source: NormalizedSharedSourceConfig;
output: NormalizedSharedOutputConfig;
security?: SharedSecurityConfig;
security: NormalizedSharedSecurityConfig;
performance: NormalizedSharedPerformanceConfig;
tools: SharedToolsConfig;
}>;
Expand Down
14 changes: 9 additions & 5 deletions packages/builder/builder-shared/src/types/config/security.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@ export type SriOptions = {
hashLoading?: 'eager' | 'lazy';
};

export interface CheckSyntaxOptions {
targets: string[];
exclude?: RegExp | Array<RegExp>;
}

export interface SharedSecurityConfig {
/**
* Adding an integrity attribute (`integrity`) to sub-resources introduced by HTML allows the browser to
* verify the integrity of the introduced resource, thus preventing tampering with the downloaded resource.
*/
sri?: SriOptions | boolean;
/** Analyze the product for the presence of high-level syntax that is not compatible in the specified environment */
checkSyntax?: boolean | CheckSyntaxOptions;

/**
* Adding an nonce attribute to sub-resources introduced by HTML allows the browser to
* verify the nonce of the introduced resource, thus preventing xss.
*/
nonce?: string;
}

export type NormalizedSharedSecurityConfig = Required<SharedSecurityConfig>;
1 change: 1 addition & 0 deletions packages/builder/builder-shared/src/types/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export type Plugins = {
svg: PluginsFn;
html: PluginsFn;
antd: PluginsFn;
checkSyntax: PluginsFn;
};

/**
Expand Down
5 changes: 0 additions & 5 deletions packages/builder/builder-webpack-provider/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,17 +96,13 @@
"@modern-js/types": "workspace:*",
"@modern-js/utils": "workspace:*",
"@pmmmwh/react-refresh-webpack-plugin": "0.5.9",
"acorn": "^8.8.1",
"caniuse-lite": "^1.0.30001451",
"cheerio": "1.0.0-rc.12",
"css-minimizer-webpack-plugin": "5.0.0",
"cssnano": "6.0.0",
"fork-ts-checker-webpack-plugin": "8.0.0",
"html-webpack-plugin": "5.5.0",
"mini-css-extract-plugin": "2.7.0",
"postcss": "8.4.21",
"react-refresh": "0.14.0",
"source-map": "^0.7.4",
"style-loader": "3.3.1",
"terser-webpack-plugin": "5.3.6",
"ts-loader": "9.4.1",
Expand All @@ -115,7 +111,6 @@
"devDependencies": {
"@modern-js/e2e": "workspace:*",
"@scripts/vitest-config": "workspace:*",
"@types/babel__core": "^7.20.0",
"@types/caniuse-lite": "^1.0.1",
"@types/node": "^14",
"antd": "4",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import { sharedSecurityConfigSchema, z } from '@modern-js/builder-shared';
import {
sharedSecurityConfigSchema,
z,
SriOptions,
} from '@modern-js/builder-shared';
import type { SecurityConfig } from '../../types';

export const SriOptionsSchema: z.ZodType<SriOptions> = z.partialObj({
hashFuncNames: z.array(z.string()).min(1) as unknown as z.ZodType<
[string, ...string[]]
>,
enabled: z.literals(['auto', true, false]),
hashLoading: z.literals(['eager', 'lazy']),
});

export const securityConfigSchema: z.ZodType<SecurityConfig> =
sharedSecurityConfigSchema
.extend({
checkSyntax: z.union([
z.boolean(),
z.object({
targets: z.array(z.string()),
exclude: z.optional(
z.union([z.instanceof(RegExp), z.array(z.instanceof(RegExp))]),
),
}),
]),
sri: z.union([SriOptionsSchema, z.boolean()]),
})
.partial();
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const applyDefaultPlugins = (plugins: Plugins) =>
plugins.antd(),
plugins.svg(),
import('../plugins/pug').then(m => m.builderPluginPug()),
import('../plugins/checkSyntax').then(m => m.builderPluginCheckSyntax()),
plugins.checkSyntax(),
import('../plugins/copy').then(m => m.builderPluginCopy()),
plugins.font(),
plugins.image(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import type { SharedSecurityConfig } from '@modern-js/builder-shared';

export interface CheckSyntaxOptions {
targets: string[];
exclude?: RegExp | Array<RegExp>;
}
import type {
SriOptions,
SharedSecurityConfig,
NormalizedSharedSecurityConfig,
} from '@modern-js/builder-shared';

export type SecurityConfig = SharedSecurityConfig & {
/** Analyze the product for the presence of high-level syntax that is not compatible in the specified environment */
checkSyntax?: boolean | CheckSyntaxOptions;
/**
* Adding an integrity attribute (`integrity`) to sub-resources introduced by HTML allows the browser to
* verify the integrity of the introduced resource, thus preventing tampering with the downloaded resource.
*/
sri?: SriOptions | boolean;
};

export type NormalizedSecurityConfig = Required<SecurityConfig>;
export type NormalizedSecurityConfig = NormalizedSharedSecurityConfig &
Required<Pick<SecurityConfig, 'sri'>>;

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ import {
BuilderTarget,
DEFAULT_BROWSERSLIST,
getBrowserslistWithDefault,
DefaultBuilderPlugin,
SharedNormalizedConfig,
} from '@modern-js/builder-shared';
import type { BuilderPlugin, NormalizedConfig } from '../types';

export function builderPluginCheckSyntax(): BuilderPlugin {
export function builderPluginCheckSyntax(): DefaultBuilderPlugin {
return {
name: 'builder-plugin-check-syntax',

setup(api) {
api.modifyWebpackChain(async (chain, { isProd, target }) => {
api.modifyBundlerChain(async (chain, { isProd, target }) => {
const config = api.getNormalizedConfig();
const { checkSyntax } = config.security;

Expand All @@ -29,9 +30,7 @@ export function builderPluginCheckSyntax(): BuilderPlugin {
target,
checkSyntax,
);
const { CheckSyntaxPlugin } = await import(
'../webpackPlugins/CheckSyntaxPlugin'
);
const { CheckSyntaxPlugin } = await import('@modern-js/builder-shared');
chain.plugin(CheckSyntaxPlugin.name).use(CheckSyntaxPlugin, [
{
targets,
Expand All @@ -46,7 +45,7 @@ export function builderPluginCheckSyntax(): BuilderPlugin {

async function getCheckTargets(
builderContext: BuilderContext,
builderConfig: NormalizedConfig,
builderConfig: SharedNormalizedConfig,
builderTarget: BuilderTarget,
checkSyntax: { targets: string[] } | true,
) {
Expand Down
2 changes: 2 additions & 0 deletions packages/builder/builder/src/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,6 @@ export const plugins = {
assetsRetry: () =>
import('./assetsRetry').then(m => m.builderPluginAssetsRetry()),
antd: () => import('./antd').then(m => m.builderAntdPlugin()),
checkSyntax: () =>
import('./checkSyntax').then(m => m.builderPluginCheckSyntax()),
};
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// Vitest Snapshot v1

exports[`plugins/checkSyntax > should set WebpackCheckSyntax plugin 1`] = `
exports[`plugins/check-syntax > should add check-syntax plugin properly 1`] = `
{
"plugins": [
CheckSyntaxPlugin {
"ecmaVersion": 5,
"errors": [],
"exclude": undefined,
"targets": [
"> 0.01%",
"not dead",
Expand All @@ -15,3 +16,5 @@ exports[`plugins/checkSyntax > should set WebpackCheckSyntax plugin 1`] = `
],
}
`;

exports[`plugins/check-syntax > should not add check-syntax plugin when target node 1`] = `{}`;
Loading