azproduction / lmd

LMD - JavaScript Module-Assembler for building better web applications :warning: Project is no longer supported :warning:
http://azproduction.ru/lmd/
MIT License
449 stars 27 forks source link

Glob the tree of modules #145

Closed kastigar closed 11 years ago

kastigar commented 11 years ago

Hello!

I have a problem to define my modules. I have more complicated tree of sources. I.e. my views have subviews, templates have subtemplates etc. So depth of my modules is in range from 1 to 4. I.e. the part of my source tree

app
|-- views
|   |-- account
|   |   |-- profile
|   |   |   |-- bank_form.js
|   |   |   |-- address_form.js
|   |   |-- layout.js
|   |
|   |-- top_panel.js
|
|-- application.js

"*": "*.js" - this includes only first level. "*": "**/*.js" - this is wrong I need LMD will detect all modules with preserving its relative path. In glob templates there is only: ext, file, basename, dir. I need another one, path, relative path to module: for app/application.js path = '' for app/views/top_panel.js path = 'views/' for app/views/profile/bank_form.js path = 'views/profile/' where app/ is root path.

So it will be possible to define "${path}${file}": "**/*.js" or even "**": "**/*.js" if ** would be alias for ${path}${file}.

WDYT? Is there another way to solve my requirements?

P.S. if you will accept this feature i can implement it

azproduction commented 11 years ago

Hi!

For complex application trees like this

.
└── app
    ├── views
    │   ├── account
    │   │   ├── profile
    │   │   │   ├── address_form.js
    │   │   │   └── bank_form.js
    │   │   └── layout.js
    │   └── top_panel.js
    └── application.js

You can write lmd.js config to define your special modules along with simple modules.

// .lmd/index.lmd.js
var glob = require('glob').sync,
    path = require('path');

var root = path.join(__dirname, '..', 'app');

var modules = glob(path.join(root, '**/*.js')).reduce(function (modules, fileName) {
    var relativeFileName = path.relative(root, fileName),
        moduleName = relativeFileName.replace(/\.[^.]+$/, '');

    modules[moduleName] = relativeFileName;
    return modules;
}, {});

module.exports = {
    name: "index build",
    root: "../app",
    output: "../index.lmd.js",
    modules: modules,
    main: "application"
};
$ lmd info index
info:    Module Paths, Depends and Features
info:
info:    application                         <- /Users/azproduction/Documents/tmp/test/app/application.js
info:    views/account/layout                <- /Users/azproduction/Documents/tmp/test/app/views/account/layout.js
info:    views/account/profile/address_form  <- /Users/azproduction/Documents/tmp/test/app/views/account/profile/address_form.js
info:    views/account/profile/bank_form     <- /Users/azproduction/Documents/tmp/test/app/views/account/profile/bank_form.js
info:    views/top_panel                     <- /Users/azproduction/Documents/tmp/test/app/views/top_panel.js

file, basename and dir template variables are designed for simple application layouts like this

kastigar commented 11 years ago

Thx, I've done it similar way. But I asked about config way (sorry, forgot to mention this).

azproduction commented 11 years ago

It also can be done using template expressions

{
    "name": "index build",
    "root": "../app",
    "output": "index.lmd.js",
    "modules": {
        "<%= dir.reverse().join('/').split('app/')[1] %><%= file %>": "**/*.js"
    },
    "main": "main"
}
kastigar commented 11 years ago

Ok, thx. But this example is not good. If root will be changed, I must change the template (splitter should be changed). Another issue - splitter may be present in full path somewhere else. So, what do you think about additional property? :)

azproduction commented 11 years ago

That's true. Can't we give better name to ${path} which represents "path to file from project root". ${rootpath}?

azproduction commented 11 years ago

Or probably we should introduce something like ${rootdir}?! But rootdir is bad name fot this case.

{
    "name": "index build",
    "root": "../app",
    "output": "index.lmd.js",
    "modules": {
        "<%= rootdir.reverse().join('/') %><%= file %>": "**/*.js"
    },
    "main": "main"
}

or ${depth}

{
    "name": "index build",
    "root": "../app",
    "output": "index.lmd.js",
    "modules": {
        "<%= dir.slice(0, depth).reverse().join('/') %><%= file %>": "**/*.js"
    },
    "main": "main"
}
kastigar commented 11 years ago

rootdir or rootpath sounds like path to root directory. Grunt has similar attribute named subdir. depth is generally useless, so it will be better to provide path instead of its length.

kastigar commented 11 years ago

btw, it will be better to provide it either as string or both as string and as array. Because if subdir is empty you should use empty string and if it is not you should join it with / and append with /. So, without string variant template will look like "<%= subdir.length > 0 ? subdir.reverse().join('/') + '/' : '' %><%= file %>". This is ugly, i think.

azproduction commented 11 years ago

subdir with custom toString() sounds ok. But subdir partly duplicates dir, while depth is independent, but it's use-case less obvious.

kastigar commented 11 years ago

But subdir partly duplicates dir

imho, it is not a problem. The main aim is suitable tool, isn't it?

depth's use-case less obvious.

Exactly!

azproduction commented 11 years ago

Ok, I will implement subdir!

azproduction commented 11 years ago
kastigar commented 11 years ago

Cool, thank you!