Skip to content

Parse JS imports #567

@yzqzss

Description

@yzqzss

Many modern websites now chained imports for their JavaScript.

It's time to parse JS like I used to parse CSS!

PoC:

package main

import (
	_ "embed"
	"fmt"
	"strings"

	"github.com/tdewolff/parse/v2"
	"github.com/tdewolff/parse/v2/js"
)

var src string = `
// static import
import { slice } from "lodash";
import React from 'react';

// dynamic import
import('./a.js');
import("b.js").then(() => console.log('loaded'));
`

func extractImportStrings(ast *js.AST) []string {
	var imports []string
	js.Walk(&importVisitor{imports: &imports}, ast)
	return imports
}

type importVisitor struct {
	imports *[]string
}

func (v *importVisitor) Enter(n js.INode) js.IVisitor {
	if call, ok := n.(*js.CallExpr); ok {
		if lit, ok := call.X.(*js.LiteralExpr); ok && lit.TokenType == js.ImportToken {
			if len(call.Args.List) > 0 {
				if strLit, ok := call.Args.List[0].Value.(*js.LiteralExpr); ok && strLit.TokenType == js.StringToken {
					*v.imports = append(*v.imports, strings.Trim(string(strLit.Data), `"'`))
				}
			}
		}
	}
	if importStmt, ok := n.(*js.ImportStmt); ok {
		*v.imports = append(*v.imports, strings.Trim(string(importStmt.Module), `"'`))
	}
	return v
}

func (v *importVisitor) Exit(n js.INode) {}

func main() {
	input := parse.NewInput(strings.NewReader(src))
	ast, err := js.Parse(input, js.Options{})
	if err != nil {
		panic(err)
	}

	importStrings := extractImportStrings(ast)
	fmt.Println("Extracted import() strings:")
	for _, s := range importStrings {
		fmt.Println(s)
	}
}

stdout:

Extracted import() strings:
lodash
react
./a.js
b.js

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions