diff --git a/packages/editor/gulpfile.js b/packages/editor/gulpfile.js index ec138f7c7..e0c76ff70 100644 --- a/packages/editor/gulpfile.js +++ b/packages/editor/gulpfile.js @@ -1,5 +1,6 @@ /* global require, __dirname -- Globals defined by Nodejs */ +const fs = require('node:fs'); const path = require('node:path'); const utils = require('@gravity-ui/gulp-utils'); @@ -46,7 +47,39 @@ gulp.task('scss', () => { .pipe(gulp.dest(BUILD_DIR)); }); -gulp.task('build', gulp.parallel('ts', 'json', 'scss')); +gulp.task('styles-string', (done) => { + // External CSS files imported directly from @diplodoc/* packages in TS source. + // These are not processed by the 'scss' task and would be missing from styles.css. + const externalCssPaths = [ + require.resolve('@diplodoc/transform/dist/css/base.css'), + require.resolve('@diplodoc/transform/dist/css/_yfm-only.css'), + require.resolve('@diplodoc/cut-extension/runtime/styles.css'), + require.resolve('@diplodoc/file-extension/runtime/styles.css'), + require.resolve('@diplodoc/tabs-extension/runtime/styles.css'), + require.resolve('@diplodoc/quote-link-extension/runtime/styles.css'), + require.resolve('@diplodoc/folding-headings-extension/runtime/styles.css'), + ]; + + const externalCss = externalCssPaths.map((p) => fs.readFileSync(p, 'utf8')).join('\n'); + const editorCss = fs.readFileSync(path.join(BUILD_DIR, 'styles.css'), 'utf8'); + const css = externalCss + '\n' + editorCss; + + const escaped = css.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$\{/g, '\\${'); + const content = `\`${escaped}\``; + + // Use .mjs extension: always treated as ESM regardless of package.json "type" field. + // A plain .js in the build root (which has no "type": "module") would cause + // SyntaxError: Unexpected token 'export' when required as CommonJS. + fs.writeFileSync(path.join(BUILD_DIR, 'styles-string.mjs'), `export default ${content};\n`); + fs.writeFileSync(path.join(BUILD_DIR, 'styles-string.cjs'), `module.exports = ${content};\n`); + fs.writeFileSync( + path.join(BUILD_DIR, 'styles-string.d.ts'), + `declare const styles: string;\nexport default styles;\n`, + ); + done(); +}); + +gulp.task('build', gulp.series(gulp.parallel('ts', 'json', 'scss'), 'styles-string')); gulp.task('default', gulp.series('clean', 'build')); diff --git a/packages/editor/package.json b/packages/editor/package.json index dca838210..9037a3bd5 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -152,6 +152,16 @@ "default": "./build/cjs/*" } }, + "./styles-string": { + "import": { + "types": "./build/styles-string.d.ts", + "default": "./build/styles-string.mjs" + }, + "require": { + "types": "./build/styles-string.d.ts", + "default": "./build/styles-string.cjs" + } + }, "./styles/*": "./build/esm/styles/*" }, "main": "build/cjs/index.js", diff --git a/packages/editor/tests/esbuild-test/esbuild-tester.js b/packages/editor/tests/esbuild-test/esbuild-tester.js index 3e1e9f447..d80b4cca4 100644 --- a/packages/editor/tests/esbuild-test/esbuild-tester.js +++ b/packages/editor/tests/esbuild-test/esbuild-tester.js @@ -38,6 +38,20 @@ const esbuildOptions = { alias: ['fs', 'path', 'stream'].reduce((acc, name) => ({...acc, [name]: paths.aliases}), {}), }; +// Smoke test: verify styles-string export before esbuild bundling test +const stylesStringCjs = require(path.join(__dirname, '../../build/styles-string.cjs')); +if (typeof stylesStringCjs !== 'string' || stylesStringCjs.length === 0) { + throw new Error('styles-string CJS export is invalid: expected non-empty string'); +} +const stylesStringMjs = fs.readFileSync( + path.join(__dirname, '../../build/styles-string.mjs'), + 'utf8', +); +if (!stylesStringMjs.startsWith('export default `')) { + throw new Error('styles-string ESM file is invalid: expected "export default `..."'); +} +console.log('styles-string smoke test: OK (length:', stylesStringCjs.length, ')'); + esbuild .build({...esbuildOptions, entryPoints: [paths.esbuildToTest]}) .then(async () => {