Add ESM distributions for browser (#8983)
Co-authored-by: fisker <lionkay@gmail.com>
This commit is contained in:
1 parent
e857c4e88f
commit
549090a5ba
8 files changed
+164
-32
No files matched your search
@@ -0,0 +1,13 @@
|
||||
#### ESM standalone bundles ([#8983](https://github.com/prettier/prettier/pull/8983) by [@Monchi](https://github.com/Monchi), [@fisker](https://github.com/fisker))
|
||||
|
||||
Now standalone is also bundled as ESM. It works directly on browser.
|
||||
|
||||
```js
|
||||
import prettier from "https://unpkg.com/prettier/esm/standalone.mjs";
|
||||
import parserGraphql from "https://unpkg.com/prettier/esm/parser-graphql.mjs";
|
||||
|
||||
prettier.format("query { }", {
|
||||
parser: "graphql",
|
||||
plugins: [parserGraphql],
|
||||
});
|
||||
```
|
||||
+2
-2
@@ -33,8 +33,8 @@ Note that the [`unpkg` field](https://unpkg.com/#examples) in Prettier’s `pack
|
||||
### ES Modules
|
||||
|
||||
```js
|
||||
import prettier from "prettier/standalone";
|
||||
import parserGraphql from "prettier/parser-graphql";
|
||||
import prettier from "https://unpkg.com/prettier/esm/standalone.mjs";
|
||||
import parserGraphql from "https://unpkg.com/prettier/esm/parser-graphql.mjs";
|
||||
|
||||
prettier.format("query { }", {
|
||||
parser: "graphql",
|
||||
|
||||
+32
-5
@@ -2,12 +2,41 @@
|
||||
|
||||
const installPrettier = require("./scripts/install-prettier");
|
||||
|
||||
const isProduction = process.env.NODE_ENV === "production";
|
||||
const ENABLE_CODE_COVERAGE = !!process.env.ENABLE_CODE_COVERAGE;
|
||||
if (process.env.NODE_ENV === "production" || process.env.INSTALL_PACKAGE) {
|
||||
if (isProduction || process.env.INSTALL_PACKAGE) {
|
||||
process.env.PRETTIER_DIR = installPrettier();
|
||||
}
|
||||
const { TEST_STANDALONE } = process.env;
|
||||
|
||||
const testPathIgnorePatterns = [];
|
||||
let transform;
|
||||
if (TEST_STANDALONE) {
|
||||
testPathIgnorePatterns.push("<rootDir>/tests_integration/");
|
||||
}
|
||||
if (isProduction) {
|
||||
// `esm` bundles need transform
|
||||
transform = {
|
||||
"(?:\\.mjs|codeSamples\\.js)$": [
|
||||
"babel-jest",
|
||||
{
|
||||
presets: [
|
||||
[
|
||||
"@babel/env",
|
||||
// Workaround for https://github.com/babel/babel/issues/11994
|
||||
{ loose: true },
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
} else {
|
||||
// Only test bundles for production
|
||||
testPathIgnorePatterns.push(
|
||||
"<rootDir>/tests_integration/__tests__/bundle.js"
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
setupFiles: ["<rootDir>/tests_config/setup.js"],
|
||||
snapshotSerializers: [
|
||||
@@ -15,9 +44,7 @@ module.exports = {
|
||||
"jest-snapshot-serializer-ansi",
|
||||
],
|
||||
testRegex: "jsfmt\\.spec\\.js$|__tests__/.*\\.js$",
|
||||
testPathIgnorePatterns: TEST_STANDALONE
|
||||
? ["<rootDir>/tests_integration/"]
|
||||
: [],
|
||||
testPathIgnorePatterns,
|
||||
collectCoverage: ENABLE_CODE_COVERAGE,
|
||||
collectCoverageFrom: ["<rootDir>/src/**/*.js", "<rootDir>/bin/**/*.js"],
|
||||
coveragePathIgnorePatterns: ["<rootDir>/src/document/doc-debug.js"],
|
||||
@@ -28,7 +55,7 @@ module.exports = {
|
||||
},
|
||||
modulePathIgnorePatterns: ["<rootDir>/dist"],
|
||||
testEnvironment: "node",
|
||||
transform: {},
|
||||
transform,
|
||||
watchPlugins: [
|
||||
"jest-watch-typeahead/filename",
|
||||
"jest-watch-typeahead/testname",
|
||||
|
||||
+10
-6
@@ -22,7 +22,7 @@ process.on("unhandledRejection", (err) => {
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
const CACHE_VERSION = "v30"; // This need update when updating build scripts
|
||||
const CACHE_VERSION = "v31"; // This need update when updating build scripts
|
||||
const CACHED = chalk.bgYellow.black(" CACHED ");
|
||||
const OK = chalk.bgGreen.black(" DONE ");
|
||||
const FAIL = chalk.bgRed.black(" FAIL ");
|
||||
@@ -72,15 +72,18 @@ function handleError(error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
async function cacheFiles() {
|
||||
async function cacheFiles(cache) {
|
||||
// Copy built files to .cache
|
||||
try {
|
||||
await execa("rm", ["-rf", path.join(".cache", "files")]);
|
||||
await execa("mkdir", ["-p", path.join(".cache", "files")]);
|
||||
for (const bundleConfig of bundleConfigs) {
|
||||
await execa("mkdir", ["-p", path.join(".cache", "files", "esm")]);
|
||||
const manifest = cache.updated;
|
||||
|
||||
for (const file of Object.keys(manifest.files)) {
|
||||
await execa("cp", [
|
||||
path.join("dist", bundleConfig.output),
|
||||
path.join(".cache", "files"),
|
||||
file,
|
||||
path.join(".cache", file.replace("dist", "files")),
|
||||
]);
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -107,6 +110,7 @@ async function preparePackage() {
|
||||
async function run(params) {
|
||||
await execa("rm", ["-rf", "dist"]);
|
||||
await execa("mkdir", ["-p", "dist"]);
|
||||
await execa("mkdir", ["-p", "dist/esm"]);
|
||||
|
||||
if (params["purge-cache"]) {
|
||||
await execa("rm", ["-rf", ".cache"]);
|
||||
@@ -120,7 +124,7 @@ async function run(params) {
|
||||
await createBundle(bundleConfig, bundleCache);
|
||||
}
|
||||
|
||||
await cacheFiles();
|
||||
await cacheFiles(bundleCache);
|
||||
await bundleCache.save();
|
||||
|
||||
await preparePackage();
|
||||
|
||||
+53
-18
@@ -182,7 +182,13 @@ function getRollupConfig(bundle) {
|
||||
externals(bundle.externals),
|
||||
bundle.target === "universal" && nodeGlobals(),
|
||||
babel(babelConfig),
|
||||
bundle.minify !== false && bundle.target === "universal" && terser(),
|
||||
bundle.minify !== false &&
|
||||
bundle.target === "universal" &&
|
||||
terser({
|
||||
output: {
|
||||
ascii_only: true,
|
||||
},
|
||||
}),
|
||||
].filter(Boolean);
|
||||
|
||||
if (bundle.target === "node") {
|
||||
@@ -202,11 +208,25 @@ function getRollupOutputOptions(bundle) {
|
||||
if (bundle.target === "node") {
|
||||
options.format = "cjs";
|
||||
} else if (bundle.target === "universal") {
|
||||
options.format = "umd";
|
||||
options.name =
|
||||
bundle.type === "plugin" ? `prettierPlugins.${bundle.name}` : bundle.name;
|
||||
|
||||
if (!bundle.format && bundle.bundler !== "webpack") {
|
||||
return [
|
||||
{
|
||||
...options,
|
||||
format: "umd",
|
||||
},
|
||||
{
|
||||
...options,
|
||||
format: "esm",
|
||||
file: `dist/esm/${bundle.output.replace(".js", ".mjs")}`,
|
||||
},
|
||||
];
|
||||
}
|
||||
options.format = bundle.format;
|
||||
}
|
||||
return options;
|
||||
return [options];
|
||||
}
|
||||
|
||||
function getWebpackConfig(bundle) {
|
||||
@@ -261,32 +281,47 @@ function runWebpack(config) {
|
||||
});
|
||||
}
|
||||
|
||||
async function checkCache(cache, inputOptions, outputOption) {
|
||||
const useCache = await cache.checkBundle(
|
||||
outputOption.file,
|
||||
inputOptions,
|
||||
outputOption
|
||||
);
|
||||
|
||||
if (useCache) {
|
||||
try {
|
||||
await execa("cp", [
|
||||
path.join(cache.cacheDir, outputOption.file.replace("dist", "files")),
|
||||
outputOption.file,
|
||||
]);
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
// Proceed to build
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
module.exports = async function createBundle(bundle, cache) {
|
||||
const inputOptions = getRollupConfig(bundle);
|
||||
const outputOptions = getRollupOutputOptions(bundle);
|
||||
|
||||
const useCache = await cache.checkBundle(
|
||||
bundle.output,
|
||||
inputOptions,
|
||||
outputOptions
|
||||
const checkCacheResults = await Promise.all(
|
||||
outputOptions.map((outputOption) =>
|
||||
checkCache(cache, inputOptions, outputOption)
|
||||
)
|
||||
);
|
||||
if (useCache) {
|
||||
try {
|
||||
await execa("cp", [
|
||||
path.join(cache.cacheDir, "files", bundle.output),
|
||||
"dist",
|
||||
]);
|
||||
return { cached: true };
|
||||
} catch (err) {
|
||||
// Proceed to build
|
||||
}
|
||||
if (checkCacheResults.every((r) => r === true)) {
|
||||
return { cached: true };
|
||||
}
|
||||
|
||||
if (bundle.bundler === "webpack") {
|
||||
await runWebpack(getWebpackConfig(bundle));
|
||||
} else {
|
||||
const result = await rollup(inputOptions);
|
||||
await result.write(outputOptions);
|
||||
await Promise.all(outputOptions.map((option) => result.write(option)));
|
||||
}
|
||||
|
||||
return { bundled: true };
|
||||
|
||||
@@ -7,7 +7,7 @@ const path = require("path");
|
||||
* @property {string} input - input of the bundle
|
||||
* @property {string?} output - path of the output file in the `dist/` folder
|
||||
* @property {string?} name - name for the UMD bundle (for plugins, it'll be `prettierPlugins.${name}`)
|
||||
* @property {'node' | 'universal'} target - should generate a CJS only for node or UMD bundle
|
||||
* @property {'node' | 'universal'} target - should generate a CJS only for node or universal bundle
|
||||
* @property {'core' | 'plugin'} type - it's a plugin bundle or core part of prettier
|
||||
* @property {'rollup' | 'webpack'} [bundler='rollup'] - define which bundler to use
|
||||
* @property {CommonJSConfig} [commonjs={}] - options for `rollup-plugin-commonjs`
|
||||
@@ -66,6 +66,11 @@ const parsers = [
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "dist/parser-postcss.js",
|
||||
output: "esm/parser-postcss.mjs",
|
||||
format: "esm",
|
||||
},
|
||||
{
|
||||
input: "src/language-graphql/parser-graphql.js",
|
||||
},
|
||||
@@ -109,6 +114,7 @@ const coreBundles = [
|
||||
type: "core",
|
||||
output: "doc.js",
|
||||
target: "universal",
|
||||
format: "umd",
|
||||
minify: false,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
"use strict";
|
||||
|
||||
const path = require("path");
|
||||
const globby = require("globby");
|
||||
const { projectRoot } = require("../env");
|
||||
const coreOptions = require("../../src/main/core-options");
|
||||
const codeSamples = require("../../website/playground/codeSamples").default;
|
||||
|
||||
const parserNames = coreOptions.options.parser.choices.map(
|
||||
({ value }) => value
|
||||
);
|
||||
const distDirectory = path.join(projectRoot, "dist");
|
||||
|
||||
describe("standalone", () => {
|
||||
const standalone = require(path.join(distDirectory, "standalone.js"));
|
||||
const plugins = globby
|
||||
.sync(["parser-*.js"], { cwd: distDirectory, absolute: true })
|
||||
.map((file) => require(file));
|
||||
|
||||
const esmStandalone = require(path.join(distDirectory, "esm/standalone.mjs"))
|
||||
.default;
|
||||
const esmPlugins = globby
|
||||
.sync(["esm/parser-*.mjs"], { cwd: distDirectory, absolute: true })
|
||||
.map((file) => require(file).default);
|
||||
|
||||
for (const parser of parserNames) {
|
||||
test(parser, () => {
|
||||
const input = codeSamples(parser);
|
||||
const umdOutput = standalone.format(input, {
|
||||
parser,
|
||||
plugins,
|
||||
});
|
||||
|
||||
expect(typeof input).toBe("string");
|
||||
expect(typeof umdOutput).toBe("string");
|
||||
expect(umdOutput).not.toBe(input);
|
||||
|
||||
const esmOutput = esmStandalone.format(input, {
|
||||
parser,
|
||||
plugins: esmPlugins,
|
||||
});
|
||||
|
||||
expect(esmOutput).toBe(umdOutput);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -18,6 +18,7 @@ const thirdParty = isProduction
|
||||
const projectRoot = path.join(__dirname, "..");
|
||||
|
||||
module.exports = {
|
||||
isProduction,
|
||||
thirdParty,
|
||||
prettierCli,
|
||||
projectRoot,
|
||||
|
||||
Reference in new issue
Block a user