Skip to content

Commit

Permalink
feat: support format option for transform
Browse files Browse the repository at this point in the history
This allows to use `transform` to output a different format without
going through `build` which would resolve all imports.

Import handling:

- `cjs`: imports are not resolved and re-written as `require` calls
- `iife`: any import will through
  • Loading branch information
sastan committed Sep 4, 2020
1 parent 95c7713 commit aa4cc2f
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 5 deletions.
2 changes: 1 addition & 1 deletion internal/bundler/bundler.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ func parseFile(args parseArgs) {
if args.options.IsBundling {
result.resolveResults = make([]*resolver.ResolveResult, len(result.file.ast.ImportRecords))

if len(result.file.ast.ImportRecords) > 0 {
if len(result.file.ast.ImportRecords) > 0 && !(args.options.IsTransforming && args.options.OutputFormat != config.FormatIIFE) {
cache := make(map[string]*resolver.ResolveResult)

// Resolve relative to the parent directory of the source file with the
Expand Down
3 changes: 2 additions & 1 deletion internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ type ExternalModules struct {
type Options struct {
// true: imports are scanned and bundled along with the file
// false: imports are left alone and the file is passed through as-is
IsBundling bool
IsBundling bool
IsTransforming bool

RemoveWhitespace bool
MinifyIdentifiers bool
Expand Down
3 changes: 2 additions & 1 deletion lib/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ function pushCommonFlags(flags: string[], options: types.CommonOptions, isTTY: b
if (options.minifyWhitespace) flags.push('--minify-whitespace');
if (options.minifyIdentifiers) flags.push('--minify-identifiers');

if (options.format) flags.push(`--format=${options.format}`);

if (options.jsxFactory) flags.push(`--jsx-factory=${options.jsxFactory}`);
if (options.jsxFragment) flags.push(`--jsx-fragment=${options.jsxFragment}`);
if (options.define) {
Expand Down Expand Up @@ -50,7 +52,6 @@ function flagsForBuildOptions(options: types.BuildOptions, isTTY: boolean): [str
if (options.outfile) flags.push(`--outfile=${options.outfile}`);
if (options.outdir) flags.push(`--outdir=${options.outdir}`);
if (options.platform) flags.push(`--platform=${options.platform}`);
if (options.format) flags.push(`--format=${options.format}`);
if (options.tsconfig) flags.push(`--tsconfig=${options.tsconfig}`);
if (options.resolveExtensions) flags.push(`--resolve-extensions=${options.resolveExtensions.join(',')}`);
if (options.external) for (let name of options.external) flags.push(`--external:${name}`);
Expand Down
3 changes: 2 additions & 1 deletion lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export interface CommonOptions {
target?: string | string[];
strict?: boolean | Strict[];

format?: Format;

minify?: boolean;
minifyWhitespace?: boolean;
minifyIdentifiers?: boolean;
Expand All @@ -32,7 +34,6 @@ export interface BuildOptions extends CommonOptions {
metafile?: string;
outdir?: string;
platform?: Platform;
format?: Format;
color?: boolean;
external?: string[];
loader?: { [ext: string]: Loader };
Expand Down
2 changes: 2 additions & 0 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,8 @@ type TransformOptions struct {
Defines map[string]string
PureFunctions []string

Format Format

Sourcefile string
Loader Loader
}
Expand Down
9 changes: 9 additions & 0 deletions pkg/api/api_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,7 @@ func transformImpl(input string, transformOpts TransformOptions) TransformResult

// Convert and validate the transformOpts
options := config.Options{
IsTransforming: true,
UnsupportedFeatures: validateFeatures(log, transformOpts.Target, transformOpts.Engines),
Strict: validateStrict(transformOpts.Strict),
JSX: config.JSXOptions{
Expand All @@ -603,13 +604,21 @@ func transformImpl(input string, transformOpts TransformOptions) TransformResult
MangleSyntax: transformOpts.MinifySyntax,
RemoveWhitespace: transformOpts.MinifyWhitespace,
MinifyIdentifiers: transformOpts.MinifyIdentifiers,
OutputFormat: validateFormat(transformOpts.Format),
AbsOutputFile: transformOpts.Sourcefile + "-out",
Stdin: &config.StdinInfo{
Loader: validateLoader(transformOpts.Loader),
Contents: input,
SourceFile: transformOpts.Sourcefile,
},
}

if options.OutputFormat == config.FormatESModule {
options.OutputFormat = config.FormatPreserve
} else if options.OutputFormat != config.FormatPreserve {
options.IsBundling = true
}

if options.SourceMap == config.SourceMapLinkedWithComment {
// Linked source maps don't make sense because there's no output file name
log.AddError(nil, ast.Loc{}, "Cannot transform with linked source maps")
Expand Down
14 changes: 13 additions & 1 deletion pkg/cli/cli_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,15 +238,27 @@ func parseOptionsImpl(osArgs []string, buildOpts *api.BuildOptions, transformOpt
return fmt.Errorf("Invalid platform: %q (valid: browser, node)", value)
}

case strings.HasPrefix(arg, "--format=") && buildOpts != nil:
case strings.HasPrefix(arg, "--format="):
value := arg[len("--format="):]
switch value {
case "iife":
if buildOpts != nil {
buildOpts.Format = api.FormatIIFE
} else {
transformOpts.Format = api.FormatIIFE
}
case "cjs":
if buildOpts != nil {
buildOpts.Format = api.FormatCommonJS
} else {
transformOpts.Format = api.FormatCommonJS
}
case "esm":
if buildOpts != nil {
buildOpts.Format = api.FormatESModule
} else {
transformOpts.Format = api.FormatESModule
}
default:
return fmt.Errorf("Invalid format: %q (valid: iife, cjs, esm)", value)
}
Expand Down
32 changes: 32 additions & 0 deletions scripts/js-api-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,38 @@ let transformTests = {
assert.strictEqual(js, `export const foo = 123;\n`)
},

async esm_to_esm({ service }) {
const { js } = await service.transform(`import path from 'path';export default path`, { format: 'esm' })

assert.strictEqual(js, `import path2 from "path";\nexport default path2;\n`)
},

async esm_to_cjs({ service, testDir }) {
const { js } = await service.transform(`import path from 'path';export default path`, { format: 'cjs' })

const output = path.join(testDir, 'out.js')
await writeFileAsync(output, js)
const result = require(output)
assert.strictEqual(result.default, path)
assert.strictEqual(result.__esModule, true)
},

async esm_to_iife({ service, testDir }) {
const { js } = await service.transform(`const a = document.querySelector('.a')`, { format: 'iife' })

assert.strictEqual(js, `(() => {\n // <stdin>\n const a = document.querySelector(".a");\n})();\n`)
},

async esm_to_iife_with_import({ service, testDir }) {
try {
await service.transform(`import path from 'path';export default path`, { format: 'iife' })

assert.fail('iife can not import')
} catch (error) {
assert.strictEqual(error.message, `Transform failed with 1 error:\n<stdin>:1:17: error: Could not resolve "path"`)
}
},

async jsx({ service }) {
const { js } = await service.transform(`console.log(<div/>)`, { loader: 'jsx' })
assert.strictEqual(js, `console.log(/* @__PURE__ */ React.createElement("div", null));\n`)
Expand Down

0 comments on commit aa4cc2f

Please sign in to comment.