From 655fc12fcbfbdc8b981d70514ae90a7e0c2ca853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Fri, 14 Aug 2020 21:02:39 +0900 Subject: [PATCH] Make spack respect swcrc (#964) --- bundler/Cargo.toml | 2 +- bundler/src/bundler/load.rs | 3 +- node-swc/src/{spack/index.ts => spack.ts} | 10 +- package.json | 2 +- scripts/coverage.sh | 1 + spack/integration-tests/react/.gitignore | 1 + spack/integration-tests/react/package.json | 7 +- spack/integration-tests/react/spack.config.js | 8 +- spack/integration-tests/react/src/.swcrc | 8 + spack/integration-tests/react/src/index.ts | 2 - spack/integration-tests/react/src/index.tsx | 8 + spack/src/loaders/swc.rs | 140 +++++++++++++----- spack/tests/fixture.rs | 9 +- .../pass/swcrc/jsx/issue-884/output/entry.jsx | 2 +- .../tree-shaking/in-module/output/entry.js | 3 +- 15 files changed, 149 insertions(+), 57 deletions(-) rename node-swc/src/{spack/index.ts => spack.ts} (82%) create mode 100644 spack/integration-tests/react/.gitignore create mode 100644 spack/integration-tests/react/src/.swcrc delete mode 100644 spack/integration-tests/react/src/index.ts create mode 100644 spack/integration-tests/react/src/index.tsx diff --git a/bundler/Cargo.toml b/bundler/Cargo.toml index e72bac5461e..6ce19988175 100644 --- a/bundler/Cargo.toml +++ b/bundler/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swc_bundler" -version = "0.1.0" +version = "0.1.1" authors = ["강동윤 "] license = "Apache-2.0/MIT" repository = "https://github.com/swc-project/swc.git" diff --git a/bundler/src/bundler/load.rs b/bundler/src/bundler/load.rs index de0961bfad6..c952094112c 100644 --- a/bundler/src/bundler/load.rs +++ b/bundler/src/bundler/load.rs @@ -84,8 +84,7 @@ where // Do tasks in parallel, and then wait for result for result in results { - let res = result?; - dbg!(res.is_none()); + result?; } Ok(Some(v)) diff --git a/node-swc/src/spack/index.ts b/node-swc/src/spack.ts similarity index 82% rename from node-swc/src/spack/index.ts rename to node-swc/src/spack.ts index bb046303532..2bd26706d1a 100644 --- a/node-swc/src/spack/index.ts +++ b/node-swc/src/spack.ts @@ -1,10 +1,10 @@ -import { Options } from "../types"; +import { Options } from "./types"; import * as path from 'path'; export type BundleInput = BundleOptions | BundleOptions[]; -export async function compileBundleOptions(c: BundleInput | string | undefined): Promise { - const f = c === undefined ? '.' : c; +export async function compileBundleOptions(config: BundleInput | string | undefined): Promise { + const f = config === undefined ? '.' : config; try { const file = typeof f === 'string' ? f : path.resolve('spack.config.js'); @@ -21,10 +21,10 @@ export async function compileBundleOptions(c: BundleInput | string | undefined): } return configFromFile; } - return Object.assign({}, configFromFile, c); + return Object.assign({}, configFromFile, config); } catch (e) { if (typeof f === 'string') { - throw new Error(`Config file does not exist at ${c}`) + throw new Error(`Error occurred while loading config file at ${config}: ${e}`); } return f; } diff --git a/package.json b/package.json index 6be1fd5f8d6..7723a754c9d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@swc/core", - "version": "1.2.19", + "version": "1.2.20", "description": "Super-fast alternative for babel", "main": "./index.js", "author": "강동윤 ", diff --git a/scripts/coverage.sh b/scripts/coverage.sh index cb1e626a9a1..9a508185e16 100755 --- a/scripts/coverage.sh +++ b/scripts/coverage.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash set -eu +export RUST_MIN_STACK=$((1024*1024*16)) export CARGO_INCREMENTAL=0 export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests" export RUSTDOCFLAGS="-Cpanic=abort" diff --git a/spack/integration-tests/react/.gitignore b/spack/integration-tests/react/.gitignore new file mode 100644 index 00000000000..f1ff06d608f --- /dev/null +++ b/spack/integration-tests/react/.gitignore @@ -0,0 +1 @@ +lib/ \ No newline at end of file diff --git a/spack/integration-tests/react/package.json b/spack/integration-tests/react/package.json index 6d1f70d6b32..3b8ded5aeb0 100644 --- a/spack/integration-tests/react/package.json +++ b/spack/integration-tests/react/package.json @@ -11,9 +11,12 @@ "author": "", "license": "ISC", "dependencies": { - "react": "^16.13.1" + "@swc/helpers": "^0.2.0", + "react": "^16.13.1", + "react-dom": "^16.13.1" }, "devDependencies": { - "@types/react": "^16.9.44" + "@types/react": "^16.9.44", + "@types/react-dom": "^16.9.8" } } diff --git a/spack/integration-tests/react/spack.config.js b/spack/integration-tests/react/spack.config.js index 91740c49566..05466edb9d1 100644 --- a/spack/integration-tests/react/spack.config.js +++ b/spack/integration-tests/react/spack.config.js @@ -1,12 +1,10 @@ -const { config } = require('@swc/core/spack') -module.exports = config({ +module.exports = { entry: { - 'web': __dirname + '/src/index.ts', + 'web': __dirname + '/src/index.tsx', }, output: { path: __dirname + '/lib' }, - module: {}, -}); \ No newline at end of file +}; \ No newline at end of file diff --git a/spack/integration-tests/react/src/.swcrc b/spack/integration-tests/react/src/.swcrc new file mode 100644 index 00000000000..2b266ff2eb5 --- /dev/null +++ b/spack/integration-tests/react/src/.swcrc @@ -0,0 +1,8 @@ +{ + "jsc": { + "parser": { + "syntax": "ecmascript", + "jsx": true + } + } +} diff --git a/spack/integration-tests/react/src/index.ts b/spack/integration-tests/react/src/index.ts deleted file mode 100644 index 968290fa16c..00000000000 --- a/spack/integration-tests/react/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import React from 'react'; - diff --git a/spack/integration-tests/react/src/index.tsx b/spack/integration-tests/react/src/index.tsx new file mode 100644 index 00000000000..777e4b2fffb --- /dev/null +++ b/spack/integration-tests/react/src/index.tsx @@ -0,0 +1,8 @@ +import React from "react"; +import ReactDom from "react-dom"; + +function App() { + return
; +} + +ReactDom.render(, document.getElementById("root")); diff --git a/spack/src/loaders/swc.rs b/spack/src/loaders/swc.rs index cd60f9e50d5..6f56a3628c3 100644 --- a/spack/src/loaders/swc.rs +++ b/spack/src/loaders/swc.rs @@ -1,9 +1,20 @@ use anyhow::{bail, Context, Error}; -use std::sync::Arc; +use helpers::Helpers; +use std::{collections::HashMap, env, sync::Arc}; +use swc::config::{InputSourceMap, JscConfig, TransformConfig}; +use swc_atoms::JsWord; use swc_bundler::Load; -use swc_common::{FileName, SourceFile}; -use swc_ecma_ast::{Module, Program}; +use swc_common::{FileName, SourceFile, DUMMY_SP}; +use swc_ecma_ast::{Expr, Lit, Module, Program, Str}; use swc_ecma_parser::JscTarget; +use swc_ecma_transforms::{ + helpers, + optimization::{ + simplify::{dead_branch_remover, expr_simplifier}, + InlineGlobals, + }, +}; +use swc_ecma_visit::FoldWith; /// JavaScript loader pub struct SwcLoader { @@ -17,36 +28,6 @@ impl SwcLoader { options.config = Some(Default::default()); } - { - let v = options.config.as_mut().unwrap(); - // TODO: Some(Esm) - v.module = None; - v.minify = Some(false); - - v.jsc.target = JscTarget::Es2020; - - if v.jsc.transform.is_none() { - v.jsc.transform = Some(Default::default()); - } - - let mut transform = v.jsc.transform.as_mut().unwrap(); - if transform.optimizer.is_none() { - transform.optimizer = Some(Default::default()); - } - - let mut opt = transform.optimizer.as_mut().unwrap(); - if opt.globals.is_none() { - opt.globals = Some(Default::default()); - } - - // Always inline NODE_ENV - opt.globals - .as_mut() - .unwrap() - .envs - .insert("NODE_ENV".to_string()); - } - SwcLoader { compiler, options } } } @@ -66,7 +47,59 @@ impl Load for SwcLoader { log::trace!("JsLoader.load: loaded"); - let config = self.compiler.config_for_file(&self.options, &fm.name)?; + let mut config = self.compiler.config_for_file( + &swc::config::Options { + config: { + if let Some(c) = &self.options.config { + Some(swc::config::Config { + jsc: JscConfig { + transform: { + if let Some(c) = &c.jsc.transform { + Some(TransformConfig { + react: c.react.clone(), + const_modules: c.const_modules.clone(), + optimizer: None, + legacy_decorator: c.legacy_decorator, + decorator_metadata: c.decorator_metadata, + }) + } else { + None + } + }, + external_helpers: true, + ..c.jsc + }, + module: None, + minify: Some(false), + ..c.clone() + }) + } else { + None + } + }, + disable_hygiene: false, + disable_fixer: true, + global_mark: self.options.global_mark, + cwd: self.options.cwd.clone(), + caller: None, + filename: String::new(), + config_file: None, + root: None, + root_mode: Default::default(), + swcrc: true, + swcrc_roots: Default::default(), + env_name: { + let s = env::var("NODE_ENV").unwrap_or_else(|_| "development".into()); + s + }, + input_source_map: InputSourceMap::Bool(false), + source_maps: None, + source_file_name: None, + source_root: None, + is_module: true, + }, + &fm.name, + )?; log::trace!("JsLoader.load: loaded config"); @@ -75,11 +108,25 @@ impl Load for SwcLoader { // Note that we don't apply compat transform at loading phase. let program = self.compiler - .parse_js(fm.clone(), JscTarget::Es2019, config.syntax, true, true)?; + .parse_js(fm.clone(), JscTarget::Es2020, config.syntax, true, true)?; log::trace!("JsLoader.load: parsed"); - let program = self.compiler.transform(program, true, config.pass); + // Fold module + let program = helpers::HELPERS.set(&Helpers::new(true), || { + swc_ecma_utils::HANDLER.set(&self.compiler.handler, || { + let program = program.fold_with(&mut InlineGlobals { + envs: env_map(), + globals: Default::default(), + }); + let program = program.fold_with(&mut expr_simplifier()); + let program = program.fold_with(&mut dead_branch_remover()); + + let program = program.fold_with(&mut config.pass); + + program + }) + }); log::trace!("JsLoader.load: applied transforms"); @@ -89,3 +136,24 @@ impl Load for SwcLoader { } } } + +fn env_map() -> HashMap { + let mut m = HashMap::default(); + + { + let s = env::var("NODE_ENV") + .map(|v| JsWord::from(v)) + .unwrap_or_else(|_| "development".into()); + + m.insert( + "NODE_ENV".into(), + Expr::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: s, + has_escape: false, + })), + ); + } + + m +} diff --git a/spack/tests/fixture.rs b/spack/tests/fixture.rs index c929c3d5399..217c3391479 100644 --- a/spack/tests/fixture.rs +++ b/spack/tests/fixture.rs @@ -14,6 +14,8 @@ use std::{ use swc::config::SourceMapsConfig; use swc_bundler::{BundleKind, Bundler, Config}; use swc_common::{FileName, GLOBALS}; +use swc_ecma_transforms::fixer; +use swc_ecma_visit::FoldWith; use test::{ test_main, DynTestFn, Options, ShouldPanic::No, TestDesc, TestDescAndFn, TestName, TestType, }; @@ -181,7 +183,12 @@ fn reference_tests(tests: &mut Vec, errors: bool) -> Result<(), i for bundled in modules { let code = compiler - .print(&bundled.module, SourceMapsConfig::Bool(false), None, false) + .print( + &bundled.module.fold_with(&mut fixer(None)), + SourceMapsConfig::Bool(false), + None, + false, + ) .expect("failed to print?") .code; diff --git a/spack/tests/pass/swcrc/jsx/issue-884/output/entry.jsx b/spack/tests/pass/swcrc/jsx/issue-884/output/entry.jsx index fa258e3b0fb..5f95f3bde1d 100644 --- a/spack/tests/pass/swcrc/jsx/issue-884/output/entry.jsx +++ b/spack/tests/pass/swcrc/jsx/issue-884/output/entry.jsx @@ -1,4 +1,4 @@ /** * Don't ask why it is named as divider. */ -export const Divider = React.createElement("div", null); +export var Divider = React.createElement("div", null); diff --git a/spack/tests/pass/tree-shaking/in-module/output/entry.js b/spack/tests/pass/tree-shaking/in-module/output/entry.js index e00b68aa31a..93f63904e26 100644 --- a/spack/tests/pass/tree-shaking/in-module/output/entry.js +++ b/spack/tests/pass/tree-shaking/in-module/output/entry.js @@ -1 +1,2 @@ -console.log(2); +let a = 2; +console.log(a);