Add ESM distributions for browser (#8983)

Co-authored-by: fisker <lionkay@gmail.com>
This commit is contained in:
Yuku Kotaniandfisker authored and GitHub committed 2020-09-17 00:08:44 +08:00
1 parent e857c4e88f
commit 549090a5ba
8 files changed
+164 -32

No files matched your search

+13
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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,
},
{
+46
View File
@@ -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);
});
}
});
+1
View File
@@ -18,6 +18,7 @@ const thirdParty = isProduction
const projectRoot = path.join(__dirname, "..");
module.exports = {
isProduction,
thirdParty,
prettierCli,
projectRoot,