diff --git a/Cargo.lock b/Cargo.lock index 4b00dcf8723..372b61c8b7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1056,11 +1056,10 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" dependencies = [ - "matches", "percent-encoding", ] @@ -1362,11 +1361,10 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" dependencies = [ - "matches", "unicode-bidi", "unicode-normalization", ] @@ -1644,12 +1642,6 @@ dependencies = [ "regex-automata", ] -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - [[package]] name = "memchr" version = "2.4.1" @@ -2105,9 +2097,9 @@ checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "petgraph" @@ -3132,6 +3124,7 @@ dependencies = [ "swc_visit", "testing", "tracing", + "url", "walkdir", ] @@ -4950,13 +4943,12 @@ checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "url" -version = "2.2.2" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" dependencies = [ "form_urlencoded", "idna", - "matches", "percent-encoding", ] diff --git a/crates/swc/Cargo.toml b/crates/swc/Cargo.toml index acaf45092b7..ca65da2875e 100644 --- a/crates/swc/Cargo.toml +++ b/crates/swc/Cargo.toml @@ -98,6 +98,7 @@ swc_plugin_runner = { version = "0.78.1", path = "../swc_plugin_runner", optiona swc_timer = { version = "0.17.17", path = "../swc_timer" } swc_visit = { version = "0.5.2", path = "../swc_visit" } tracing = "0.1.32" +url = "2.3.1" [dependencies.napi-derive] default-features = false diff --git a/crates/swc/src/lib.rs b/crates/swc/src/lib.rs index d932c295743..ed98192dd11 100644 --- a/crates/swc/src/lib.rs +++ b/crates/swc/src/lib.rs @@ -158,6 +158,7 @@ use swc_ecma_visit::{noop_visit_type, FoldWith, Visit, VisitMutWith, VisitWith}; pub use swc_error_reporters::handler::{try_with_handler, HandlerOpts}; pub use swc_node_comments::SwcComments; use swc_timer::timer; +use url::Url; pub use crate::builder::PassBuilder; use crate::config::{ @@ -328,20 +329,35 @@ impl Compiler { } InputSourceMap::Str(ref s) => { if s == "inline" { + const NEEDLE: &str = "sourceMappingURL="; // Load inline source map by simple string // operations - let s = "sourceMappingURL=data:application/json;base64,"; - let idx = fm.src.rfind(s); + let idx = fm.src.rfind(NEEDLE); let idx = match idx { None => bail!( "failed to parse inline source map: `sourceMappingURL` not found" ), Some(v) => v, }; - let encoded = &fm.src[idx + s.len()..]; + let data_url = fm.src[idx + NEEDLE.len()..].trim(); + let url = Url::parse(data_url).with_context(|| { + format!("failed to parse inline source map url\n{}", data_url) + })?; - let res = base64::decode(encoded.as_bytes()) - .context("failed to decode base64-encoded source map")?; + let idx = match url.path().find("base64,") { + Some(v) => v, + None => { + bail!("failed to parse inline source map: not base64: {:?}", url) + } + }; + + let content = url.path()[idx + "base64,".len()..].trim(); + + let res = base64::decode_config( + content.as_bytes(), + base64::Config::new(base64::CharacterSet::Standard, true), + ) + .context("failed to decode base64-encoded source map")?; Ok(Some(sourcemap::SourceMap::from_slice(&res).context( "failed to read input source map from inlined base64 encoded string", diff --git a/crates/swc/tests/fixture/next-39878/input/.swcrc b/crates/swc/tests/fixture/next-39878/input/.swcrc new file mode 100644 index 00000000000..6e06bc9f452 --- /dev/null +++ b/crates/swc/tests/fixture/next-39878/input/.swcrc @@ -0,0 +1,14 @@ +{ + "env": { + "targets": { + "chrome": "95" + } + }, + "jsc": { + "parser": { + "syntax": "typescript", + "tsx": true + } + }, + "sourceMaps": true +} \ No newline at end of file diff --git a/crates/swc/tests/fixture/next-39878/input/box-model.ts b/crates/swc/tests/fixture/next-39878/input/box-model.ts new file mode 100644 index 00000000000..ad2e1d29868 --- /dev/null +++ b/crates/swc/tests/fixture/next-39878/input/box-model.ts @@ -0,0 +1,63 @@ +import type { UIStore, UIThunkAction } from "ui/actions"; +import { isInspectorSelected } from "ui/reducers/app"; +import { AppStartListening } from "ui/setup/listenerMiddleware"; +import { getBoundingRectAsync, getComputedStyleAsync } from "ui/suspense/styleCaches"; + +import { nodeSelected } from "../../markup/reducers/markup"; +import { LAYOUT_NUMERIC_FIELDS, Layout, layoutUpdated } from "../reducers/box-model"; + +export function setupBoxModel(store: UIStore, startAppListening: AppStartListening) { + // Any time a new node is selected in the "Markup" panel, + // try to update the box model layout data + startAppListening({ + actionCreator: nodeSelected, + effect: async (action, listenerApi) => { + const { extra, getState, dispatch } = listenerApi; + const { ThreadFront, protocolClient, replayClient } = extra; + const state = getState(); + const { selectedNode, tree } = state.markup; + + if (!isInspectorSelected(state) || !selectedNode || !ThreadFront.currentPause?.pauseId) { + return; + } + + const nodeInfo = tree.entities[selectedNode]; + + if (!nodeInfo) { + return; + } + + const [bounds, style] = await Promise.all([ + getBoundingRectAsync( + protocolClient, + ThreadFront.sessionId!, + ThreadFront.currentPause.pauseId, + selectedNode + ), + getComputedStyleAsync( + protocolClient, + ThreadFront.sessionId!, + ThreadFront.currentPause.pauseId, + selectedNode + ), + ]); + + if (!bounds || !style) { + return; + } + + const layout = { + width: parseFloat(bounds.width.toPrecision(6)), + height: parseFloat(bounds.height.toPrecision(6)), + autoMargins: {}, + } as Layout; + + for (const prop of LAYOUT_NUMERIC_FIELDS) { + layout[prop] = style.get(prop)!; + } + + // Update the redux store with the latest layout properties and update the box model view. + dispatch(layoutUpdated(layout)); + }, + }); +} diff --git a/crates/swc/tests/fixture/next-39878/output/box-model.map b/crates/swc/tests/fixture/next-39878/output/box-model.map new file mode 100644 index 00000000000..e42f93e262e --- /dev/null +++ b/crates/swc/tests/fixture/next-39878/output/box-model.map @@ -0,0 +1,52 @@ +{ + "mappings": "AACA,SAASA,mBAAmB,QAAQ,kBAAkB;AAEtD,SAASC,oBAAoB,EAAEC,qBAAqB,QAAQ,0BAA0B;AAEtF,SAASC,YAAY,QAAQ,+BAA+B;AAC5D,SAASC,qBAAqB,EAAUC,aAAa,QAAQ,wBAAwB;AAErF,OAAO,SAASC,cAAcC,KAAc,EAAEC,iBAAoC,EAAE;IAClF,yDAAyD;IACzD,0CAA0C;IAC1CA,kBAAkB;QAChBC,eAAeN;QACfO,QAAQ,OAAOC,QAAQC,cAAgB;YACrC,MAAM,EAAEC,MAAK,EAAEC,SAAQ,EAAEC,SAAQ,EAAE,GAAGH;YACtC,MAAM,EAAEI,YAAW,EAAEC,eAAc,EAAEC,aAAY,EAAE,GAAGL;YACtD,MAAMM,QAAQL;YACd,MAAM,EAAEM,aAAY,EAAEC,KAAI,EAAE,GAAGF,MAAMG,MAAM;YAE3C,IAAI,CAACtB,oBAAoBmB,UAAU,CAACC,gBAAgB,CAACJ,YAAYO,YAAY,EAAEC,SAAS;gBACtF;YACF,CAAC;YAED,MAAMC,WAAWJ,KAAKK,QAAQ,CAACN,aAAa;YAE5C,IAAI,CAACK,UAAU;gBACb;YACF,CAAC;YAED,MAAM,CAACE,QAAQC,MAAM,GAAG,MAAMC,QAAQC,GAAG,CAAC;gBACxC7B,qBACEgB,gBACAD,YAAYe,SAAS,EACrBf,YAAYO,YAAY,CAACC,OAAO,EAChCJ;gBAEFlB,sBACEe,gBACAD,YAAYe,SAAS,EACrBf,YAAYO,YAAY,CAACC,OAAO,EAChCJ;aAEH;YAED,IAAI,CAACO,UAAU,CAACC,OAAO;gBACrB;YACF,CAAC;YAED,MAAMI,SAAS;gBACbC,OAAOC,WAAWP,OAAOM,KAAK,CAACE,WAAW,CAAC;gBAC3CC,QAAQF,WAAWP,OAAOS,MAAM,CAACD,WAAW,CAAC;gBAC7CE,aAAa,CAAC;YAChB;YAEA,KAAK,MAAMC,QAAQlC,sBAAuB;gBACxC4B,MAAM,CAACM,KAAK,GAAGV,MAAMW,GAAG,CAACD;YAC3B;YAEA,0FAA0F;YAC1FvB,SAASV,cAAc2B;QACzB;IACF;AACF,CAAC", + "names": [ + "isInspectorSelected", + "getBoundingRectAsync", + "getComputedStyleAsync", + "nodeSelected", + "LAYOUT_NUMERIC_FIELDS", + "layoutUpdated", + "setupBoxModel", + "store", + "startAppListening", + "actionCreator", + "effect", + "action", + "listenerApi", + "extra", + "getState", + "dispatch", + "ThreadFront", + "protocolClient", + "replayClient", + "state", + "selectedNode", + "tree", + "markup", + "currentPause", + "pauseId", + "nodeInfo", + "entities", + "bounds", + "style", + "Promise", + "all", + "sessionId", + "layout", + "width", + "parseFloat", + "toPrecision", + "height", + "autoMargins", + "prop", + "get" + ], + "sources": [ + "../../input/box-model.ts" + ], + "sourcesContent": [ + "import type { UIStore, UIThunkAction } from \"ui/actions\";\nimport { isInspectorSelected } from \"ui/reducers/app\";\nimport { AppStartListening } from \"ui/setup/listenerMiddleware\";\nimport { getBoundingRectAsync, getComputedStyleAsync } from \"ui/suspense/styleCaches\";\n\nimport { nodeSelected } from \"../../markup/reducers/markup\";\nimport { LAYOUT_NUMERIC_FIELDS, Layout, layoutUpdated } from \"../reducers/box-model\";\n\nexport function setupBoxModel(store: UIStore, startAppListening: AppStartListening) {\n // Any time a new node is selected in the \"Markup\" panel,\n // try to update the box model layout data\n startAppListening({\n actionCreator: nodeSelected,\n effect: async (action, listenerApi) => {\n const { extra, getState, dispatch } = listenerApi;\n const { ThreadFront, protocolClient, replayClient } = extra;\n const state = getState();\n const { selectedNode, tree } = state.markup;\n\n if (!isInspectorSelected(state) || !selectedNode || !ThreadFront.currentPause?.pauseId) {\n return;\n }\n\n const nodeInfo = tree.entities[selectedNode];\n\n if (!nodeInfo) {\n return;\n }\n\n const [bounds, style] = await Promise.all([\n getBoundingRectAsync(\n protocolClient,\n ThreadFront.sessionId!,\n ThreadFront.currentPause.pauseId,\n selectedNode\n ),\n getComputedStyleAsync(\n protocolClient,\n ThreadFront.sessionId!,\n ThreadFront.currentPause.pauseId,\n selectedNode\n ),\n ]);\n\n if (!bounds || !style) {\n return;\n }\n\n const layout = {\n width: parseFloat(bounds.width.toPrecision(6)),\n height: parseFloat(bounds.height.toPrecision(6)),\n autoMargins: {},\n } as Layout;\n\n for (const prop of LAYOUT_NUMERIC_FIELDS) {\n layout[prop] = style.get(prop)!;\n }\n\n // Update the redux store with the latest layout properties and update the box model view.\n dispatch(layoutUpdated(layout));\n },\n });\n}\n" + ], + "version": 3 +} diff --git a/crates/swc/tests/fixture/next-39878/output/box-model.ts b/crates/swc/tests/fixture/next-39878/output/box-model.ts new file mode 100644 index 00000000000..9d396f14fe5 --- /dev/null +++ b/crates/swc/tests/fixture/next-39878/output/box-model.ts @@ -0,0 +1,41 @@ +import { isInspectorSelected } from "ui/reducers/app"; +import { getBoundingRectAsync, getComputedStyleAsync } from "ui/suspense/styleCaches"; +import { nodeSelected } from "../../markup/reducers/markup"; +import { LAYOUT_NUMERIC_FIELDS, layoutUpdated } from "../reducers/box-model"; +export function setupBoxModel(store, startAppListening) { + // Any time a new node is selected in the "Markup" panel, + // try to update the box model layout data + startAppListening({ + actionCreator: nodeSelected, + effect: async (action, listenerApi)=>{ + const { extra , getState , dispatch } = listenerApi; + const { ThreadFront , protocolClient , replayClient } = extra; + const state = getState(); + const { selectedNode , tree } = state.markup; + if (!isInspectorSelected(state) || !selectedNode || !ThreadFront.currentPause?.pauseId) { + return; + } + const nodeInfo = tree.entities[selectedNode]; + if (!nodeInfo) { + return; + } + const [bounds, style] = await Promise.all([ + getBoundingRectAsync(protocolClient, ThreadFront.sessionId, ThreadFront.currentPause.pauseId, selectedNode), + getComputedStyleAsync(protocolClient, ThreadFront.sessionId, ThreadFront.currentPause.pauseId, selectedNode) + ]); + if (!bounds || !style) { + return; + } + const layout = { + width: parseFloat(bounds.width.toPrecision(6)), + height: parseFloat(bounds.height.toPrecision(6)), + autoMargins: {} + }; + for (const prop of LAYOUT_NUMERIC_FIELDS){ + layout[prop] = style.get(prop); + } + // Update the redux store with the latest layout properties and update the box model view. + dispatch(layoutUpdated(layout)); + } + }); +} diff --git a/crates/swc/tests/fixture/sourcemap/004/input/index.js b/crates/swc/tests/fixture/sourcemap/004/input/index.js index 675b15ec622..5d190d16eb1 100644 --- a/crates/swc/tests/fixture/sourcemap/004/input/index.js +++ b/crates/swc/tests/fixture/sourcemap/004/input/index.js @@ -1,64 +1,42 @@ -(self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([ - [158], +(self.webpackChunk_N_E = self.webpackChunk_N_E || []).push([ + [ + 158 + ], { - /***/ 2943: /***/ function ( - __unused_webpack_module, - __webpack_exports__, - __webpack_require__ - ) { + 2943: function(n, t, u) { "use strict"; - __webpack_require__.r(__webpack_exports__); - /* harmony export */ __webpack_require__.d(__webpack_exports__, { - /* harmony export */ __N_SSG: function () { - return /* binding */ __N_SSG; - }, - /* harmony export */ default: function () { - return /* binding */ StaticPage; - }, - /* harmony export */ - }); - /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = - __webpack_require__(4512); - - var __N_SSG = true; - function StaticPage(_ref) { - var data = _ref.data; - return /*#__PURE__*/ (0, - react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { - children: data.foo, + var r = function(n) { + var t = n.data; + return (0, _.jsx)("div", { + children: t.foo }); - } - - /***/ + }; + u.r(t), u.d(t, { + __N_SSG: function() { + return i; + }, + default: function() { + return r; + } + }); + var _ = u(4512), i = !0; }, - - /***/ 7139: /***/ function ( - __unused_webpack_module, - __unused_webpack_exports, - __webpack_require__ - ) { + 7139: function(n, t, u) { (window.__NEXT_P = window.__NEXT_P || []).push([ "/static", - function () { - return __webpack_require__(2943); - }, + function() { + return u(2943); + } ]); - if (false) { - } - - /***/ - }, - }, - /******/ function (__webpack_require__) { - // webpackRuntimeModules - /******/ var __webpack_exec__ = function (moduleId) { - return __webpack_require__((__webpack_require__.s = moduleId)); - }; - /******/ __webpack_require__.O(0, [774, 888, 179], function () { - return __webpack_exec__(7139); - }); - /******/ var __webpack_exports__ = __webpack_require__.O(); - /******/ _N_E = __webpack_exports__; - /******/ + } }, + function(n) { + n.O(0, [ + 774, + 888, + 179 + ], function() { + return n(n.s = 7139); + }), _N_E = n.O(); + } ]); diff --git a/crates/swc/tests/fixture/sourcemap/004/input/index.js.map b/crates/swc/tests/fixture/sourcemap/004/input/index.js.map index b428506d10d..e48482e3bee 100644 --- a/crates/swc/tests/fixture/sourcemap/004/input/index.js.map +++ b/crates/swc/tests/fixture/sourcemap/004/input/index.js.map @@ -1,18 +1,34 @@ { - "version": 3, - "file": "x", - "mappings": ";;;;;;;;;;;;;;AAAe,SAASA,UAAT,OAA8B;AAAA,MAARC,IAAQ,QAARA,IAAQ;AAC3C,sBAAO;AAAA,cAAMA,IAAI,CAACC;AAAX,IAAP;AACD;;;;;;;;ACDD;AACA;AACA;AACA,eAAe,mBAAO,CAAC,IAA8B;AACrD;AACA;AACA,OAAO,KAAU,EAAE,EAId;AACL", - "sources": [ - "webpack://./pages/static.js", - "webpack://../../../packages/next/dist/build/webpack/loaders/next-client-pages-loader.js?page=%2Fstatic&absolutePagePath=private-next-pages%2Fstatic.js!" - ], - "sourcesContent": [ - "export default function StaticPage({ data }) {\n return