How to import modules in Swift's JavaScriptCore?

前端 未结 3 794
一生所求
一生所求 2021-02-05 18:16

I\'m trying to use Swift\'s JavaScriptCore framework to take advantage of an existing JavaScript library that uses ES6 modules. Specifically, morse-pro by Stephen C Phillips. I\

3条回答
  •  太阳男子
    2021-02-05 18:59

    While using import for modules is not possible.

    You can support require('path/filename'); syntax.

    This is done by providing require as a function to JS. The import command is (unfortunately) too exotic to implement in the given restrictions of JSContext.

    See the following implementations

    Objective-C.

    @interface MyContext ()
    @property JSContext *context;
    
    @implementation MyContext
    
    - (void) setupRequire {
        MyContext * __weak weakSelf = self;
    
        self.context[@"require"] = ^(NSString *path) {
    
            path = [weakSelf resolvePath:path];
    
            if(![[NSFileManager defaultManager] fileExistsAtPath:path]) {
                NSString *message = [NSString stringWithFormat:@"Require: File “%@” does not exist.", path];
                weakSelf.context.exception = [JSValue valueWithNewErrorFromMessage:message inContext:weakSelf.context];
                return;
            }
    
            [weakSelf loadScript:path];
        };
    } 
    
    - (NSString *) resolvePath:(NSString *)path {
        path = path.stringByResolvingSymlinksInPath;
        return path.stringByStandardizingPath;
    }
    
    - (void) loadScript:(NSString *)path {
        NSError *error;
        NSString *script = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
    
        if (error) {
            script = @"";
            NSLog(@"Error: Could not read file in path “%@” to string. (%@)", path, error);
            // Return void or throw an error here.
            return
        }
    
        [self.context evaluateScript:script];
    }
    

    This example is based on code in Phoenix https://github.com/kasper/phoenix

    https://github.com/kasper/phoenix/blob/master/Phoenix/PHContext.m#L195-L206

    Swift 4

    This example is based on code in CutBox https://github.com/cutbox/CutBox

    import JavascriptCore
    
    class JSService {
    
        let context = JSContext()
    
        let shared = JSService()
    
        let require: @convention(block) (String) -> (JSValue?) = { path in
            let expandedPath = NSString(string: path).expandingTildeInPath
    
            // Return void or throw an error here.
            guard FileManager.default.fileExists(atPath: expandedPath)
                else { debugPrint("Require: filename \(expandedPath) does not exist")
                       return nil }
    
            guard let fileContent = try? String(contentsOfFile: expandedFilename) 
                else { return nil }
    
            return JSService.shared.context.evaluateScript(fileContent)
        }
    
        init() {
            self.context.setObject(self.require, 
                                   forKeyedSubscript: "require" as NSString)
        }
    
        func repl(_ string: String) -> String {
            return self.context.evaluateScript(string).toString()
        }
    }
    

提交回复
热议问题