Skip to content

Commit

Permalink
Merge branch 'canary' into fix/taint-experimental
Browse files Browse the repository at this point in the history
  • Loading branch information
ztanner authored Oct 24, 2023
2 parents f299b86 + 741a08b commit 222cbf1
Show file tree
Hide file tree
Showing 44 changed files with 789 additions and 240 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build_and_deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ jobs:
name: stable - ${{ matrix.settings.target }} - node@16
runs-on: ${{ matrix.settings.host }}
timeout-minutes: 45
timeout-minutes: 30
steps:
# https://github.com/actions/virtual-environments/issues/1187
- name: tune linux network
Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@
"registry": "https://registry.npmjs.org/"
}
},
"version": "13.5.7-canary.22"
"version": "13.5.7-canary.23"
}
2 changes: 1 addition & 1 deletion packages/create-next-app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-next-app",
"version": "13.5.7-canary.22",
"version": "13.5.7-canary.23",
"keywords": [
"react",
"next",
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-config-next/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eslint-config-next",
"version": "13.5.7-canary.22",
"version": "13.5.7-canary.23",
"description": "ESLint configuration used by Next.js.",
"main": "index.js",
"license": "MIT",
Expand All @@ -10,7 +10,7 @@
},
"homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config",
"dependencies": {
"@next/eslint-plugin-next": "13.5.7-canary.22",
"@next/eslint-plugin-next": "13.5.7-canary.23",
"@rushstack/eslint-patch": "^1.3.3",
"@typescript-eslint/parser": "^5.4.2 || ^6.0.0",
"eslint-import-resolver-node": "^0.3.6",
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin-next/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/eslint-plugin-next",
"version": "13.5.7-canary.22",
"version": "13.5.7-canary.23",
"description": "ESLint plugin for Next.js.",
"main": "dist/index.js",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/font/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/font",
"version": "13.5.7-canary.22",
"version": "13.5.7-canary.23",
"repository": {
"url": "vercel/next.js",
"directory": "packages/font"
Expand Down
2 changes: 1 addition & 1 deletion packages/next-bundle-analyzer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/bundle-analyzer",
"version": "13.5.7-canary.22",
"version": "13.5.7-canary.23",
"main": "index.js",
"types": "index.d.ts",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-codemod/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/codemod",
"version": "13.5.7-canary.22",
"version": "13.5.7-canary.23",
"license": "MIT",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-env/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/env",
"version": "13.5.7-canary.22",
"version": "13.5.7-canary.23",
"keywords": [
"react",
"next",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-mdx/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/mdx",
"version": "13.5.7-canary.22",
"version": "13.5.7-canary.23",
"main": "index.js",
"license": "MIT",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/next-plugin-storybook/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/plugin-storybook",
"version": "13.5.7-canary.22",
"version": "13.5.7-canary.23",
"repository": {
"url": "vercel/next.js",
"directory": "packages/next-plugin-storybook"
Expand Down
2 changes: 1 addition & 1 deletion packages/next-polyfill-module/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/polyfill-module",
"version": "13.5.7-canary.22",
"version": "13.5.7-canary.23",
"description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)",
"main": "dist/polyfill-module.js",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-polyfill-nomodule/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/polyfill-nomodule",
"version": "13.5.7-canary.22",
"version": "13.5.7-canary.23",
"description": "A polyfill for non-dead, nomodule browsers.",
"main": "dist/polyfill-nomodule.js",
"license": "MIT",
Expand Down
104 changes: 104 additions & 0 deletions packages/next-swc/crates/core/src/import_analyzer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use turbopack_binding::swc::core::{
atoms::JsWord,
common::collections::{AHashMap, AHashSet},
ecma::{
ast::{
Expr, Id, ImportDecl, ImportNamedSpecifier, ImportSpecifier, MemberExpr, MemberProp,
Module, ModuleExportName,
},
visit::{noop_visit_type, Visit, VisitWith},
},
};

#[derive(Debug, Default)]
pub(crate) struct ImportMap {
/// Map from module name to (module path, exported symbol)
imports: AHashMap<Id, (JsWord, JsWord)>,

namespace_imports: AHashMap<Id, JsWord>,

imported_modules: AHashSet<JsWord>,
}

#[allow(unused)]
impl ImportMap {
pub fn is_module_imported(&mut self, module: &JsWord) -> bool {
self.imported_modules.contains(module)
}

/// Returns true if `e` is an import of `orig_name` from `module`.
pub fn is_import(&self, e: &Expr, module: &str, orig_name: &str) -> bool {
match e {
Expr::Ident(i) => {
if let Some((i_src, i_sym)) = self.imports.get(&i.to_id()) {
i_src == module && i_sym == orig_name
} else {
false
}
}

Expr::Member(MemberExpr {
obj: box Expr::Ident(obj),
prop: MemberProp::Ident(prop),
..
}) => {
if let Some(obj_src) = self.namespace_imports.get(&obj.to_id()) {
obj_src == module && prop.sym == *orig_name
} else {
false
}
}

_ => false,
}
}

pub fn analyze(m: &Module) -> Self {
let mut data = ImportMap::default();

m.visit_with(&mut Analyzer { data: &mut data });

data
}
}

struct Analyzer<'a> {
data: &'a mut ImportMap,
}

impl Visit for Analyzer<'_> {
noop_visit_type!();

fn visit_import_decl(&mut self, import: &ImportDecl) {
self.data.imported_modules.insert(import.src.value.clone());

for s in &import.specifiers {
let (local, orig_sym) = match s {
ImportSpecifier::Named(ImportNamedSpecifier {
local, imported, ..
}) => match imported {
Some(imported) => (local.to_id(), orig_name(imported)),
_ => (local.to_id(), local.sym.clone()),
},
ImportSpecifier::Default(s) => (s.local.to_id(), "default".into()),
ImportSpecifier::Namespace(s) => {
self.data
.namespace_imports
.insert(s.local.to_id(), import.src.value.clone());
continue;
}
};

self.data
.imports
.insert(local, (import.src.value.clone(), orig_sym));
}
}
}

fn orig_name(n: &ModuleExportName) -> JsWord {
match n {
ModuleExportName::Ident(v) => v.sym.clone(),
ModuleExportName::Str(v) => v.value.clone(),
}
}
5 changes: 4 additions & 1 deletion packages/next-swc/crates/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,13 @@ pub mod amp_attributes;
mod auto_cjs;
pub mod cjs_optimizer;
pub mod disallow_re_export_all_in_page;
mod import_analyzer;
pub mod named_import_transform;
pub mod next_ssg;
pub mod optimize_barrel;
pub mod optimize_server_react;
pub mod page_config;
pub mod pure;
pub mod react_server_components;
pub mod server_actions;
pub mod shake_exports;
Expand Down Expand Up @@ -310,7 +312,7 @@ where
Some(config) => Either::Left(server_actions::server_actions(
&file.name,
config.clone(),
comments,
comments.clone(),
)),
None => Either::Right(noop()),
},
Expand All @@ -320,6 +322,7 @@ where
},
None => Either::Right(noop()),
},
pure::pure_magic(comments),
)
}

Expand Down
88 changes: 88 additions & 0 deletions packages/next-swc/crates/core/src/pure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use turbopack_binding::swc::core::{
common::{comments::Comments, errors::HANDLER, util::take::Take, Span, Spanned, DUMMY_SP},
ecma::{
ast::{CallExpr, Callee, EmptyStmt, Expr, Module, ModuleDecl, ModuleItem, Stmt},
visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith},
},
};

use crate::import_analyzer::ImportMap;

pub fn pure_magic<C>(comments: C) -> impl Fold
where
C: Comments,
{
as_folder(PureTransform {
imports: Default::default(),
comments,
})
}

struct PureTransform<C>
where
C: Comments,
{
imports: ImportMap,
comments: C,
}

const MODULE: &str = "next/dist/build/swc/helpers";
const FN_NAME: &str = "__nextjs_pure";

impl<C> VisitMut for PureTransform<C>
where
C: Comments,
{
fn visit_mut_expr(&mut self, e: &mut Expr) {
e.visit_mut_children_with(self);

if let Expr::Call(CallExpr {
span,
callee: Callee::Expr(callee),
args,
..
}) = e
{
if !self.imports.is_import(callee, MODULE, FN_NAME) {
return;
}

if args.len() != 1 {
HANDLER.with(|handler| {
handler
.struct_span_err(*span, "markAsPure() does not support multiple arguments")
.emit();
});
return;
}

*e = *args[0].expr.take();

let mut lo = e.span().lo;
if lo.is_dummy() {
lo = Span::dummy_with_cmt().lo;
}

self.comments.add_pure_comment(lo);
}
}

fn visit_mut_module(&mut self, m: &mut Module) {
self.imports = ImportMap::analyze(m);

m.visit_mut_children_with(self);
}

fn visit_mut_module_item(&mut self, m: &mut ModuleItem) {
if let ModuleItem::ModuleDecl(ModuleDecl::Import(import)) = m {
if import.src.value == MODULE {
*m = ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }));
return;
}
}

m.visit_mut_children_with(self);
}

noop_visit_mut_type!();
}
21 changes: 21 additions & 0 deletions packages/next-swc/crates/core/tests/fixture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use next_swc::{
optimize_barrel::optimize_barrel,
optimize_server_react::optimize_server_react,
page_config::page_config_test,
pure::pure_magic,
react_server_components::server_components,
server_actions::{
server_actions, {self},
Expand Down Expand Up @@ -571,3 +572,23 @@ where
{
serde_json::from_str(s).expect("failed to deserialize")
}

#[fixture("tests/fixture/pure/**/input.js")]
fn pure(input: PathBuf) {
let output = input.parent().unwrap().join("output.js");
test_fixture(
syntax(),
&|tr| {
let unresolved_mark = Mark::new();
let top_level_mark = Mark::new();

chain!(
resolver(unresolved_mark, top_level_mark, false),
pure_magic(tr.comments.clone())
)
},
&input,
&output,
Default::default(),
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { __nextjs_pure } from 'not-next-magic'

__nextjs_pure(console.log('test!'))
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { __nextjs_pure } from 'not-next-magic';
__nextjs_pure(console.log("test!"));
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { __nextjs_pure } from 'next/dist/build/swc/helpers'

__nextjs_pure(console.log('test!'))
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
;
/*#__PURE__*/ console.log("test!");
2 changes: 1 addition & 1 deletion packages/next-swc/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/swc",
"version": "13.5.7-canary.22",
"version": "13.5.7-canary.23",
"private": true,
"scripts": {
"clean": "node ../../scripts/rm.mjs native",
Expand Down
Loading

0 comments on commit 222cbf1

Please sign in to comment.