mtasa-typescript / mtasa-lua-utils

Utility functions and transformers for MTASA Typescript To Lua compilation
MIT License
6 stars 5 forks source link

⚠️ "Remove imports => remove Lua 'requires'" breaks bundle because imports never called #24

Closed websharik closed 3 years ago

websharik commented 3 years ago

I try make bundle with low level TSTL API:

const tstl = require("typescript-to-lua")
function makeBundleFile(filePath, conf) {
  return new Promise(async (resolve, reject) => {
    try {
      let result = await tstl.transpileFiles([filePath], {
        //original from tsconfig.json (wtf mix ts and tstl)
        compilerOptions: {
          ...conf.compilerOptions
        },
        tstl: {
          ...conf.tstl
        },
        plugins: [
          ...conf.compilerOptions.plugins
        ],
        types: ["lua-types/5.1"],
        ...conf.tstl,
        //if not . then put out to src
        rootDir: ".",
        //out path with same name from src
        luaBundle: `${conf.compilerOptions.outDir}/${path.basename(filePath).replace('.ts', '.lua')}`,
        //entry point
        luaBundleEntry: filePath
      })
      console.log(result)
      resolve(result)
    } catch (e) {
      reject(e)
    }
  })
}

test_ts.ts

import { msg } from "./separatedFile"
print(`msg: ${msg}`)

separatedFile.ts

export const msg = 'Hello world'

result:

local ____modules = {}
local ____moduleCache = {}
local ____originalRequire = require
local function require(file)
    if ____moduleCache[file] then
        return ____moduleCache[file]
    end
    if ____modules[file] then
        ____moduleCache[file] = ____modules[file]()
        return ____moduleCache[file]
    else
        if ____originalRequire then
            return ____originalRequire(file)
        else
            error("module '" .. file .. "' not found")
        end
    end
end
____modules = {
["src.example.separatedFile"] = function()
local ____exports = {}
____exports.msg = "Hello world"
_G.msg = ____exports.msg
return ____exports
 end,
["src.example.test_ts"] = function()
local ____exports = {}
print("msg: " .. msg)
return ____exports
 end,
}
return require("src.example.test_ts")

src.example.separatedFile never called and msg is stay undefined

Mb add plugins option to disable remove imports ? Or else solution...

websharik commented 3 years ago

Fix for me. But its start new problem... noside files can be contain server/client imports - deep check required.

// Remove imports => remove lua 'requires'
if (anti_import_1.isImportNode(node)) {
    if (props.side != undefined) return undefined;
}
Toliak commented 3 years ago
  1. What structure of the bundle file do you expect? a. A single file for client- and server-side, like
    IS_CLIENT = _G.addBan == nil
    if (IS_CLIENT) then
    ...
    else
    ,,,
    end

    b. Separated files for client- and server-side c. Something else :)

  2. Have you tried to bypass (or remove) mtasa-lua-utils plugin (to restore import behaviour)? I have and I stucked in this.
websharik commented 3 years ago

@Toliak, 1. b :)

websharik commented 3 years ago

@Toliak, 2. Yes I try and it's working. I'm add check to utils - if side not detected then don't remove require.

Fix for me. But its start new problem... noside files can be contain server/client imports - deep check required.

// Remove imports => remove lua 'requires'
if (anti_import_1.isImportNode(node)) {
    if (props.side != undefined) return undefined;
}
Toliak commented 3 years ago

The issue about creating multiple resources in the same boilerplate should be mentioned here. So, for multiple resources the utils should generate bundled client.lua and server.lua for each resource.


What can I suggest (and, I believe, implement :D) as a solution:

  1. Custom meta file: meta.yml (because we store data in meta, not a markup) It will look like:
    
    info:
    name: My Resource 1
    type: script
    oop: true

scripts:


info: name: My Resource 2 type: script oop: true

scripts:

bundledScripts:


2. Write compiler wrapper (like you did [here](https://github.com/mtasa-typescript/mtasa-lua-utils/issues/24#issue-962798698))

3. Produce `meta.xml` files, based on `meta.yml` for each resources

Example for the `meta.yml` above:
```xml
<meta>
    <info name="My Resource 1" type="script" />
    <oop>true</oop>

    <script src="something.lua" type="server" />
</meta>
<meta>
    <info name="My Resource 2" type="script" />
    <oop>true</oop>

    <script src="another.lua" type="client" />

    <script src="entrypoint.lua" type="server" />
</meta>

In the result we will receive:

websharik commented 3 years ago

@Toliak Its good. But problem is another or im not understand suggest solution... just look code. Original (left) works, after utils (right) not works.

2021-08-07_17-52-16

Its becouse modules is table with functions, and when "require" called function from table, it start work. Utils cut all requires inside modules. Module src.example.separatedFile never called and _G.msg = ____exports.msg never working. So msg in src.example.test_ts is undefined

My resolve: if required module not from mtasa then allow import them (my upper comment). But add recursive check inside this module to check his requires to can warning "Dont mix server/client side".

My suggest: Utils config.

"plugins": [
      {
        "transform": "mtasa-lua-utils/transformer",
        "after": false,
        "allowImports": true, //disable remove non `mtasa` imports
        "globalExports": false //disable writing exports to _G
      }
    ],
websharik commented 3 years ago

@Toliak Can your release it, pls ?

Toliak commented 3 years ago

@websharik Yes, I'm going to release it as v0.2.3

v0.2 is still unstable, because I haven't tested all features yet, so, if you'll find any bugs -- feel free to comment here, or create a new issue

websharik commented 1 year ago

Here We Go Again... 2023-05-05_13-57-27

Module SandBox.server dont know Test because it import was removed. I was clone your repo and try upgrade to latest TSTL + some paths. All done without that bug. server.ts - main bundeled entry point for server. Test.ts - some external-file self resource class.

How i can disable 'removing require from self resource in bundle mode' now ?

UPD: Solved... add to prepareGlobalImports (in prepareImports.ts)

if (isLocalImport(node, context)) {
  return context.superTransformStatements(node);
}