Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

<项目目录设计规范>讨论 #13

Closed
ecomfe opened this issue Feb 20, 2013 · 40 comments
Closed

<项目目录设计规范>讨论 #13

ecomfe opened this issue Feb 20, 2013 · 40 comments
Labels

Comments

@ecomfe
Copy link
Collaborator

ecomfe commented Feb 20, 2013

<项目目录设计规范>规范草案地址为:http://fe.baidu.com/doc/ecom/std/directory.text

讨论时间:

讨论时间截止下周三(2013-2-27)凌晨12点。下周三(2013-2-27)将对有分歧的问题发起投票。
提出问题时间截止周日(2013-2-24)凌晨12点,此时间后不允许提出新的问题,可继续对已提出问题进行讨论发表意见。

请大家踊跃提问题发表意见。

@treelite
Copy link
Contributor

对于利用后端模板系统的多页面的项目而言的话,一般都要求某一个action与某一个tpl对应,在开发时期与上线部署时期,tpl的相对路径不改变能方便FE与RD双方的开发与调试。

所以可以考虑把所有的模板文件放到entry目录中(如有必要按业务逻辑建立子文件夹)。构建只对src目录(按业务逻辑建立子目录)中的JS与CSS进行合并压缩放到asset目录(此时可以直接按资源目录分成jscss, img放到css下),不处理HTML页面(或者模板文件),不生成output文件夹,上线时简单删除src目录。

另外asset目录可能无法完全自动化管理,出于对HTML页面在构建过程中尽量少改动的目的,css文件的引用还是可能会使用<link rel="stylesheet" type="text/css" href="asset/biz1.css" />的形式引入页面,然后原始的asset/biz1.css中使用@import引入具体CSS。(也可以用require来加载CSS 这样就不用手动管理原始的asset/*.css,但是页面抖动会比较厉害)

@errorrik
Copy link
Contributor

package项目src目录结构设计的问题

以esui举例,因为它是典型package项目,并且包含css和img资源引用。

现在,package下src目录设计是这样的:

src/
    js/
    css/
    img/

从业务项目的require paths配置说起

常见的场景是,我开发一个业务项目,其使用了esui,这时需要对引入lib目录的package进行require的路径映射配置。

首先,{ esui: '../lib/esui/src/js' }肯定是不行的,因为我如果require('esui'),其path将变成../lib/esui/src/js.js

那么,我们只能配置{ esui: '../lib/esui/src/js/esui' }。这种情况,js文件夹下就是这样:

src/
    js/
        esui.js
        esui/
            lib.js
            Control.js
            InputControl.js

看起来,貌似解决了一些问题。

css资源的依赖

开发业务项目时,我需要使用esui/Button,其依赖一个css资源,我们假设文件名叫button.css。那这个文件放哪里呢?按现在的规范,只能这么放:

src/
    js/
        esui.js
        esui/
            Button.js
    css/
        button.css

然后在Button.js里这么引用:require('css!../../css/button.css

看起来从路径上来说,是正确的。但是,对于Button.js,当前的moduleId是esui/Button,在这个时候,resourceId ../../css/button.css是不可normalize的,这意味着资源是不可被处理,不可被缓存的。

从上面的描述可以得出结论:esui/Button引用的资源,不可超出./,也就意味着,button.css需要放在src/js/esui或其子目录下。

再看src/js/esui,可见,这个时候,js是多余的不合时宜的。

个人觉得合适的方案

package项目src目录下

  1. 只允许直接包含以[package name]同名的js文件
  2. 其余资源需要放置于[package name]同名的目录中。
  3. package name同名的目录内,与业务项目按业务逻辑划分的目录内的组织方式一致

所以,以下两个例子都是ok的。

expamle-1:

src/
    esui.js
    esui/
        img/
        Button.js
        button.css

expamle-2:

src/
    esui.js
    esui/
        css/
            img/
            button.css
        Button.js

require path配置则可以如此:{ esui: '../lib/esui/src/esui' }

进一步,因为src下只包含[package name][package name].js,package引入工具可以将所有引入的package source都放在直接lib下,则require path配置可变成{ esui: '../lib/esui' }

当然,package通过工具引入和管理,那配置也是自动管理的,为了保证引入package的完整性,可以不使用上段说的进一步

@otakustay
Copy link
Member

关于require path的问题

我认为业务项目中,对package的引用是通过packages来配置的,而不是pathspaths是针对单个文件或有相同前缀的映射关系而处理的,并非处理package这么复杂的东西。

packages的配置中,很明确地说了对package的引用应该分为2类:

  • 对其中一个组件的引用,直接以{packageName}/{componentName}获取,如require('esui/Button')
  • 对整个package的引用,这个东西叫main

在这样的方式下,没必要把js文件夹设计成如此多层的结构,继续保持js文件夹的扁平性即可。

例如以esui为例,结构依旧是

src/
    js/
        main.js <-- main模块
        Button.js
        Control.js
        lib.js

require的配置是

packages: [
    {
        name: 'esui',
        location: '../lib/esui/src/js',
        main: 'main'
    }
]

这种情况下,require('esui')将会对应到 ../lib/esui/src/js/main.jsrequire('esui/Button')会对应 ../lib/esui/src/js/Button.js ,完全符合预期。

amdjs对packages的查找规则参考如下:

Package lookup rules use a special lookup rule when 'packageName' is used. For the "main module" of a package, instead of it being baseUrl + 'packageName' + '.js', it is:

baseUrl + (packageConfig.location || 'packageName') + '/' + (packageConfig.main || 'main') + '.js'

For 'packageName/otherId', the rule is similar to paths, but packageConfig is used instead:

baseUrl + (packageConfig.location || 'packageName') + '/' + 'otherId' + '.js'

关于CSS这东西

不理解为什么这个resource id是不能被normailize的,amdjs对loader plugin中的resource id有强制的normalize要求:

resourceId : String. The resource ID that the plugin should load. This ID MUST be normalized.

这里 不可normalize 是指在逻辑上不能做,还是技术上确实存在着障碍呢?

虽然说amdjs提供的require.toUrl会返回一个我们不期望的路径,即 esui/src/js/button/../css/button.css ,进一步处理后对应 esui/src/js/css/button.css ,但amdjs并没有要求loader plugin使用这个函数,我们完全可以根据现有的项目结构来实现一个 感觉更合理 的方法:

假设当前的module id是 esui/Button ,我倾向于用文件系统的角度去看它,认为module id是一个 文件 ,那么 从一个文件开始的相对路径 ,事实上是相对于 这个文件所在目录 的,比如说,我有一个文件是 /usr/otakustay/dev/test.js ,那么在这文件中我写了一个相对路径 ../temp/input.txt ,它的指向一定是 /usr/otakustay/temp/input.txt 而绝对不会是 /usr/otakustay/dev/input.txt

从这个角度来看, esui/Button 对应的“文件夹”其实是 esui ,加上CSS的resource id ../css/button.css ,得到的是 esui/../../css/button.css ,这是一个非常自然的过程,再加上esui的package配置,把 esui 替换成 ../lib/esui/src/js ,得到 *../lib/esui/src/js/../css/button.css * ,依此找到最终的src应该不是什么问题。

即使抛开文件系统的说法,AMD正常的relative module id似乎也是这个工作,假设我当前module是 my/foo ,在 my/foo.js 中写一个require('./bar'),映射的应该是 my/bar.js 吧,如果是 my/foo/bar.js 才显得比较奇怪吧?

综合以上,我还是不大认同要修改当前项目文件夹结构规范。

@errorrik
Copy link
Contributor

package main的悖论

在Common-Config spec里,packages被描述成一个path lookup。这个lookup,除了package main,其他的都是可以通过paths完成的(这里不是否定packages的存在,packages更清晰是肯定的)。但这里关于main就存在一个问题:require('esui')的时候,会被映射到src/js/main.js文件。那么这个时候,这个文件define时,当前的moduleId是esui呢,还是esui/main?

  • 如果是esui,那它就不能通过require( './lib' )引用esui/lib,因为对于moduleIdesui,./lib的absoluteid是lib。这不符合我们开发时的习惯,我们在写main.js的时候,想使用当前目录下lib.js定义的模块,当然直接会require( './lib' )
  • 如果是esui/main,那esui在哪里?站在package开发者的角度,比如src/js/plugin.jsesui/plugin,他要require( 'esui' )或者require( '.' ),我们去哪找这个东西?packages是引用方的配置,但开发方自己在开发时,目录结构与module也应该是正常合理,无需特殊配置就能直接运行与调试的。

对引用package中的resource normalize

Loader-plugins规定了必须normalize,确实是这样,并且这个实现肯定是loader做的,不是各个plugin本身做的。如果pluginbu提供normailze方法,loader就会使用自己的normalize方法。对于css plugin,其normalize逻辑确实应该和默认逻辑是一致的。

所以,这就是问题:

esui/Buttonrequire('css!../../css/button.css')../../css/button.css的normalize结果是../css/button.css,但它还是一个relative style的结果。假设我引用了两个package具有同样的内部目录结构设计(两个ui组件库很可能button.css相对路径会重合,甚至如果只有一个css的package,其css可能都是src/css/style.css),这就冲突了。

因为,normalize结果是非法的。

所以,我才得出之前的结论:esui/Button引用的资源,不可超出./,也就意味着,button.css需要放在src/js/esui或其子目录下。

@otakustay
Copy link
Member

关于package和main问题

我认为src/js/main.js定义的模块名是esui/main,就如同src/js/lib.js定义的模块名叫esui/lib

对于require('esui')的事,我的问题是:为啥要有这个东西?既然一个package有了main,那入口就在main,require('esui')希望得到什么?

resource normalize的问题

amdjs允许plugin做normalize方法,因为resource id是 a plugin-specific string that the loader plugins knows how to parse to load the resource ,因此plugin应该有完整的控制权,我们可以实现将resource id转为absolute path的过程再来控制缓存吧。

@errorrik
Copy link
Contributor

resource normalize的问题

By properly normalizing the resource name, it allows the loader to cache the value effectively

缓存是由loader控制的,不能由plugin控制。

然后,两个概念,toUrl和normalize是完全无关的两个事情。

  • loader 通过plugin normalize方法得到absolute resource id,然后loader用这个id对资源的控制和优化。
  • plugin使用req.toUrl对resourceId进行操作得到url,也可以不使用。但是我觉得,resourceId->url的逻辑一定是固定的,不能package开发用一套,业务项目开发用一套,那我们就得有两个不一致的css plugin了。

关于package的开发时与loader的packages配置

我认同如下的点:

在开发esui时,我的任何module id中不会出现 esui 字样

但是,回到那个问题,loader的packages配置,在处理时,是不是应该是一个纯粹的path lookup

@otakustay
Copy link
Member

第一,默认的module的normalize规则是怎么样的,module根据普通的normalize规则可以找到正确的.js文件,CSS使用同样的normalize规则,为什么就找不到了……我看了一下Loader Plugins的normailize部分,似乎并没有什么冲突的内容

第二,loader应该是这样的

  1. package中有配置,找package的location
  2. 如果没有,找paths里的配置
  3. 如果再没有,按默认规则来

amdjs没有要求package中的location再从path去做一次映射,我觉得location就是直接使用的,并非纯粹的path lookup

而在package开发过程中,作为package developer是在什么时候用自己的package的,通常是debug的时候,那么这个loader也应该配置了package选项?

@otakustay
Copy link
Member

又想了一下,感觉应该package的location和path还是有点关系的,大致的一个算法如下:

function resolveModuleURL(moduleId) {
    // 从path中找到moduleId前缀的匹配
    // 如果path中有的话,替换掉前缀
    return baseUrl + resolvedURL;
}

function resolvePackageURL(packageConfig, moduleId) {
    moduleId = moduleId || packageConfig.main;
    var url = packageConfig.location + '/' + packageConfig.main;

    return resolveModuleURL(url);
}

在这样的方案下,我也不认为package的配置有什么问题,对于esui这样的package,应该不会在paths配置中出现,仅在packages中配置

@leeight
Copy link
Member

leeight commented Feb 28, 2013

在esui/Button中require('css!../../css/button.css')。../../css/button.css的normalize结果是../css/button.css,但它还是一个relative style的结果。

这个我不太容易理解,假如esui/Button.jsabsolute Urlhttp://www.baidu.com/esui/src/js/Button.js,那么对于button.css的计算应该是http://www.baidu.com/esui/src/js/Button.js + ../../css/button.css,这个最终计算不应该是relative style吧。

@leeight
Copy link
Member

leeight commented Feb 28, 2013

@otakustay

对于require('esui')的事,我的问题是:为啥要有这个东西?既然一个package有了main,那入口就在main,require('esui')希望得到什么?

应该就是require('esui/main')的效果

@otakustay
Copy link
Member

@leeight

对于package的使用者来说,就和你说的一样,因为有packages配置,所以就是esui/main的效果

但是如果我是esui这个package的开发者,我认为package的源码中不应该出现require('.')这样的东西,而是用require('./main')来加载 main 模块,不知我们理解是不是一样

@errorrik
Copy link
Contributor

关于packages配置是否只作用于path lookup阶段

按照@otakustay的算法,是达不到@leeight 说的: 在业务项目中, require('esui') ===require('esui/main')的。因为loadModule( moduleId )的时候,会创建script标签,toUrl只在src=的时候调用。

如果想要达到require('esui') ===require('esui/main')的效果,就必须:在loadModule( moduleId )之前,nomalize的时候,用packages配置对moduleId进行处理,将esui转换成esui/main。这里是关键点。

那么,与moduleId转换相关的配置项就有两个:packagesmap,先packages处理再map处理。

require('esui')===require('esui/main')的影响

对package开发者的影响

以下场景基于现在的<项目目录设计规范>草案,esui的开发过程

场景1: require('esui')===require('esui/main')

src/
    js/
        main.js
        lib.js
        Control.js
        Button.js
        InputControl.js

main要引用Control,应该require('./Control');Control要引用main,应该require('./main')

所以baseUrl配置,看起来应该是src/js

场景2: require('esui')!==require('esui/main')

src/
    js/
        esui/
            lib.js
            Control.js
            Button.js
            InputControl.js
        esui.js

main要引用Control,应该require('esui/Control');Control要引用main,应该require('.').

所以baseUrl配置,看起来应该是src/js

以上两种场景都比较诡异,我打算参照下requirejs关于packages的描述,以及commonjs package中为什么bin通常放在root下,源码通常放在lib目录下。

但无论怎么看,js目录貌似是多余的。所以又引入下面一个问题:

package开发时对css资源的引用

关于这个问题,我又回到上面的说法:

'../css/button.css'是esui/Buttonrequire('css!../../css/button.css')处理出来的结果,这个结果代表的含义是absoluteid不是path

在实际load的时候,我们拿它去toUrl,http://www.baidu.com/esui/js + ../css/button.css,是能load到的,这个没问题。但是'../css/button.css'是不能被loader拿来做缓存的key的。

所以我认为,esui/Button引用的css资源以及其他资源,不可超出./

@otakustay
Copy link
Member

@errorrik 所说的场景2是不怎么正确的,在开发esui的时候,任何模块名都不应该含有 esui 字样,所以main引用Control不应该是require('esui/Control'),就应该是require('./Control'),即场景一,那么baseUrl是src/js与现在的规范相符。js文件夹的存在是为了把js和其它类型的资源分开来放置。

对于CSS的问题,我的疑问是,css loader plugin提供一个normalize方法,为什么这个方法要给loader../css/button.css这么个东西,而不是给loader一个absolute path让它当作缓存的key呢?

再者,即便给loader的是../css/button.css这个,loader不会再根据当前的module id来计算再缓存吗?假设这里不是CSS,我有这样的结构:

src/
    js/
        Button.js
        widget/
            complex/
                RichSelector.js

在RichSelector中,我使用require('../../Button'),超出了./的范围,loader就不能缓存了吗?我觉得这个不合理,loader应该能缓存js module,那为何css就又不行呢……

@errorrik
Copy link
Contributor

是的,我上面举的例子2是不合理的,写出来是为了显而易见的看到其不合理性。

package配置的处理问题,我待会下午先做个试验,看看情况,结果通报到此

@lkaihua
Copy link
Contributor

lkaihua commented Feb 28, 2013

这么热闹的帖子一定要赶在截止前插一楼。

@leeight
Copy link
Member

leeight commented Feb 28, 2013

@errorrik

'../css/button.css'是esui/Button和require('css!../../css/button.css')处理出来的结果,这个结果代表的含义是absoluteid不是path。

关于这个问题,我理解应该根据js的文件的路径计算出css文件的路径,不应该用../css/button.css来当做资源的Id判断是否应该缓存。

换句话说,即便定义模块的时候,显示的声明了模块Id,但是不应该用模块Id参与资源路径的计算,而是应该用模块的Url进行资源路径的计算。

@errorrik
Copy link
Contributor

关于packages配置与package开发时module的问题

https://github.com/amdjs/amdjs-tests/blob/master/tests/packagesConfig/funky/index.js

从这里可以看出,packages的main设置,当require('packagename')加载时,是做为packagename/main存在的,而不是做为packagename存在的。那这个问题,应该没有疑虑了,也能得出和我们之前大家都提到过的结论:

package在开发时module必须使用匿名id进行define,并通过relative id引用依赖。

唯一的麻烦,就是loader实现了。。。

关于package开发时css资源的放置问题

@leeight

关于这个问题,我理解应该根据js的文件的路径计算出css文件的路径,不应该用../css/button.css来当做资源的Id判断是否应该缓存。
换句话说,即便定义模块的时候,显示的声明了模块Id,但是不应该用模块Id参与资源路径的计算,而是应该用模块的Url进行资源路径的计算。

这个问题在https://github.com/amdjs/amdjs-api/wiki/Loader-Plugins里,normalize章节有描述。整篇提到的是resource id、module id,而不是path。也就是说,这货是资源标识,不是资源路径。

@otakustay

src/
    js/
        Button.js
        button.css
        widget/
            complex/
                RichSelector.js
    css/
        button.css

你的例子,widget/complex/RichSelector中:

  • 使用require('../../Button'),normalize后的结果是Button,是一个absolute id,所以没有问题。
  • 使用require('css!../../button.css'),normalize后的结果是css!button.css,是一个absolute id,所以没有问题。
  • 使用require('css!../../../css/button.css'),normalize后的结果是css!../css/button.css,是一个relative id,所以有问题。

所以我的建议是,干掉js直接src下。css资源可以直接放src下,也可以放src/css下。

@otakustay
Copy link
Member

@errorrik 看amdjs的Loader Plugin这一章的时候,其实也很困惑这个resource id是什么,从你的描述来看,一个 absolute id 是指基于 baseUrl 的id,因此如果基于 baseUrl 再有 .. 这样的东西,就会出问题,是这样吗?

另外我对于Loader Plugin章节的理解是,normalize方法由plugin提供,所以为什么始终要强调我们的css plugin或者tpl plugin要使用默认的normalize策略而产生一个 relative id 呢,假设css plugin提供normalize方法,根据我们项目结构规范,会去掉 ../css/ 这一部分,我不觉得有什么问题

@errorrik
Copy link
Contributor

@otakustay

This is useful in providing optimal caching and optimization, but it only needs to be implemented if:

the resource IDs have complex normalization
only needed if the resource name is not a module name.

@otakustay
Copy link
Member

@errorrik 所以CSS的这个resource id,不能认为是coplex normalization的情况是吧……(其实这都是扯,真要说我们因为项目结构复杂所以是complex也没人能喷)

那么我倾向于这样的方案,不知是否符合要求了

src/
    a.js
    b.js
    widget/
        w1.js
        w2.js
    css/
        a.css
        b.css
        widget/
            w1.css
            w2.css
    tpl/
        a.tpl
        b.tpl
        widget/
            w1.tpl
            w2.tpl
    img/
    swf/

@errorrik
Copy link
Contributor

errorrik commented Mar 1, 2013

Loader-Plugins spec里描述的resource id,我根据描述和index的例子,个人的理解它的意图是,complex指不是path style的resource id

@errorrik
Copy link
Contributor

errorrik commented Mar 1, 2013

@otakustay

你上面给出的例子,从css资源管理的角度来讲,是没问题的。但是我们现有的《项目目录规范》草案里,对业务目录是这么描述的:

业务项目src目录内,绝大多数情况应当(SHOULD)根据业务逻辑划分目录结构。划分出的子目录(比如下面例子中的biz1)我们称为业务目录。划分原则如下:

  1. 源文件资源不允许(MUST NOT)按资源类型划分目录,必须(MUST)按业务逻辑划分目录。源文件资源应直接置于业务目录下。即:src(含其子目录)下,不允许出现按资源类型划分的js、css、tpl目录。
  2. 内容资源允许(SHOULD)按资源类型划分目录。即:src(含其子目录)下,允许出现按资源类型划分的img、swf、font目录。
  3. 业务公共资源必须(MUST)置于common目录下,不允许(MUST NOT)直接置于src目录下。common目录也视如业务目录。如:业务公共配置module为clb/common/conf,对应文件src/common/conf.js
  4. 业务目录中,如果文件太多不好管理,需要划分子目录时,也必须(MUST)继续遵守根据业务逻辑划分的原则,划分子业务。如:下面例子中的subbiz1

所以

我觉得我们可以统一下:

  1. 既然不允许出现按资源类型划分的js、css、tpl目录,就所有类型的项目都不允许。
  2. 或者,要放开就都放开,业务项目业务目录下也允许出现css和tpl目录。

@otakustay
Copy link
Member

如果一定要2选1,我更赞同第2个方案,大家都允许出现,不过第2个方案里 .js 文件放在哪,直接放在 src/ 下吗?

我不赞同第1个方案的原因是,如果根据这个方案,那么如果是esui,则结构可能是:

src/
    common/
        lib.js
        Control.js
        Extension.js
    input/
        TextBox.js
        Select.js
        Form.js
    plain/
        Panel.js
        Link.js
    widget/
        RichSelector.js
    extension/
        DelegateDOMEvents.js

js和css放在同一目录下,这种结构我认为是OK的,只不过各控件引用lib的时候要requrie('../common/lib')比较累,但合乎情理

但其它package可能有问题:

  • 对于er,因为只有一种资源,同时也没什么模块划分,所以要在 src 下再放一个 common ,所有的js放在 common 下吗?
  • 如果一个package,他只有一个 模块 ,但有不同资源类型,要怎么放置,在 src 下只有一个文件夹叫 common 这样吗?

@errorrik
Copy link
Contributor

errorrik commented Mar 1, 2013

不是的

对于业务项目src下必须只包含业务目录,也就是说第一级是必须根据业务逻辑划分目录结构,并且业务通用目录的名称必须是common,然后里面按照上面的原则划分

package项目的src下直接按照上面的的原则划分。也就是package项目src的划分原则与业务项目业务目录划分原则保持一致。

源文件资源不允许(MUST NOT)按资源类型划分目录的例子

package项目例:

src/
    main.js
    Control.js
    Button.js
    button.css

业务项目例子:

src/
    common/
        conf.js
    biz1
        add.js
        add.css
        edit.js
        edit.css

仅仅JS资源不允许(MUST NOT)按资源类型划分目录的例子

package项目例:

src/
    main.js
    Control.js
    Button.js
    css/
        button.css
        table.css

业务项目例子:

src/
    common/
        conf.js
    biz1
        add.js
        edit.js
        css/
            add.css
            edit.css

当然,如果仅仅JS资源不允许(MUST NOT)按资源类型划分目录,那上面的例子也符合这个规范。

@otakustay
Copy link
Member

原来是这样,总算觉得自己完全理解了

这2个方案下,我选择2:

  • 确实存在有些目录下文件太多很头疼,加入package之后这种情况只会更严重
  • 在terminal打文件名只能补全一半(因为有.js和.css同名文件)不舒服

@errorrik
Copy link
Contributor

errorrik commented Mar 1, 2013

@otakustay 的意思就是自由化咯,可以增加css/tpl目录,也可以不增加放同级,项目开发者自己把握,但是不允许出现js目录

如果是这样,其他同学还有没有意见?

@otakustay
Copy link
Member

就是这个意思,无论是package还是biz的module目录,都放开限制

@leeight
Copy link
Member

leeight commented Mar 2, 2013

@errorrik

使用require('../../Button'),normalize后的结果是Button,是一个absolute id,所以没有问题。
使用require('css!../../button.css'),normalize后的结果是css!button.css,是一个absolute id,所以没有问题。
使用require('css!../../../css/button.css'),normalize后的结果是css!../css/button.css,是一个relative id,所以有问题。

为什么normalize之后还是relative style path?如果是absoulute url,我理解就没有任何问题了。

@errorrik
Copy link
Contributor

errorrik commented Mar 2, 2013

因为你的base module是widget/complex/RichSelector,../../../css/button.css的结果就是relative的。。。

@leeight
Copy link
Member

leeight commented Mar 3, 2013

我看规范里面没有说明对于resourceId的normalize一定要参考moduleId,为什么不用module Url来计算呢?即便是按照moduleId来计算,算出来的结果是relative的,但是这个应该指的是resourceId,如果我要加载这个资源的话,resource Url应该是很明确的。

@otakustay
Copy link
Member

@leeight

规范中确实没有要求resource id按照module id的方案进行normalize, @errorrik 对这个的理解是 类似path的resource id不应该有自己的normalize逻辑 ,因此css plugin应该用标准的normalize方案

resource url是用来加载资源的,但resource id是用来缓存资源的,即用来判断这个资源到底要不要去下载一下。所以resource id事实和加载资源没关系,它是relative还是absolute都无所谓

@leeight
Copy link
Member

leeight commented Mar 3, 2013

我理解resource id的用处就是按照正常的normalize方案计算出resource url,然后资源的缓存和加载都应该以resource url为准。否则我可以创造出两个不同的resource id,但是指向同样的resource url,难道要加载两次么?

@otakustay
Copy link
Member

哈哈 @leeight 提的这个情况不就是我们一直在讨论的情况嘛~

关于这个我觉得还是可以参考正常js module加载,比如这样:

// baseUrl: 'src/js/core';
require('../widget/a');
require('../../js/widget/a');

这个在js module上也超出了 baseUrl 的范围,计算出的resource id也是relative的,且和plugin无关,是不是loader本身也不会缓存?

@errorrik
Copy link
Contributor

errorrik commented Mar 3, 2013

@leeight

否则我可以创造出两个不同的resource id,但是指向同样的resource url,难道要加载两次么?

bingo

@otakustay

这个问题和baseUrl无关咯

如果是global require的话,只能使用absolute id来加载的。如果是local require的话,就看你当前的module id了。requirejs处理的很巧妙,保留第一个term,比如a/b的../../../c -> a/../../../c。a/../../../c是这个absolute id,第一位不是.或..

@otakustay
Copy link
Member

所以 esui/src/js/Button 对应的CSS如果是 ../css/Button.css 的话,保留第一个term后形成 esui/../css/Button.css ,似乎也是正确的?我们为何不这么做呢?

当然不能说这个方法没问题,假设有这样的结构

src/
    css/
        Button.css
    js/
        Button.js <-- 依赖src/css/Button.css
        css/
            Button.css
        widget/
            Button.js <-- 依赖src/js/css/Button.css

对于 js/Buttonjs/widget/Button ,都能搞出 ../css/Button.css ,不过相信没啥人能搞出这样的结构来,所以requirejs的这个策略我感觉还是很不错的

@leeight
Copy link
Member

leeight commented Mar 4, 2013

@errorrik @otakustay 现在无法理解你们在讨论啥了。貌似跟resource的加载和模块怎么定义这两个主题有些关系。

我从上面的讨论中还是无法理解为啥目录结构为啥会影响到resource的加载了(或者你们也是认为不会有影响,但是让我理解成这样子了)。

对于 js/Button 和 js/widget/Button ,都能搞出 ../css/Button.css ,不过相信没啥人能搞出这样的结构来,所以requirejs的这个策略我感觉还是很不错的

即便有人写出这种结构,两个Button.css还是能够顺利计算出absolute url,也应该可以正常加载的,这个例子有啥意义?

如果是global require的话,只能使用absolute id来加载的。如果是local require的话,就看你当前的module id了。requirejs处理的很巧妙,保留第一个term,比如a/b的../../../c -> a/../../../c。a/../../../c是这个absolute id,第一位不是.或..

这个想说明啥问题呢?

@otakustay
Copy link
Member

@leeight 我的理解是这样的:

当前的模块id是 esui/Button ,在这个模块中引用 ./Control ,能计算出另一个模块id为 esui/Control 。这个是正常的。

把这里的 esui 看成根目录 / ,如果在 esui/Button 里引用 ../SomeThing ,超出了根目录的范围,因此计算出的会是一个 相对于当前根目录的路径 ,即 ../SomeThing ,这里因为已经超过了根目录,因此不会是一个绝对的路径(因为根目录以外有什么,我们不知道)。

就是因为这个算法,一但在根目录以外,只能出个相对的路径(loader的默认算法,先不讨论我们要不要override之),所以才会有 不同模块引用不同东西产生同样的resource id 这一问题。

而requirejs对于这个问题,用了一个办法去处理,即当计算出的路径是相对路径时,加上当前模块名的第一部分,即把 ../SomeThing 变成 esui/SomeThing ,类似的概念是,我们虽然不知道根目录外有什么,但依旧能在相对路径前加个 /

@errorrik
Copy link
Contributor

errorrik commented Mar 4, 2013

关于id和url的说明

先拿module来看。通常我们define module的时候是使用匿名的,一般情况下,module id和url是对应的,但是有个例外,就是paths配置能够将id映射到非默认对应的url去。所以我们require一个module的时候,不一定是按照默认规则去取module的。由此可以得出:

  1. loader是通过id而不是通过url进行管理的
  2. id -> url是唯一的,但是一个url不一定代表一个module。(define匿名的,不同module可能会映射到同一个文件)

而且,默认规则中,id -> url的结果,是基于baseUrl的url

关于normalize

只有在module内部,使用local require的时候,才有normalize这个行为。global require是不存在normailze这么一说的。其行为包含:

  1. relative id -> toplevel id
  2. id mapping(就是让map配置生效)

对于top level的id,normailze是不会执行step1的。

require resource和require module

在下面require module的过程中:

  1. require(id) -> 2. normalized id -> 3. to url -> 4. download,肯定是在2和3之间判断module是否define,如果有,就直接return

require resource的行为和require module是一样的,也必须是一样的。我想这个没什么好质疑的。

ui/Buttonrequire('css!../../css/button.css')的normalize,无论是什么策略都:

  1. 必须是和baseUrl无关的
  2. 不允许是relative的

都是path style,当然是和默认normalize保持一致最自然。

package开发时的require resource

我为什么一直_强调_在ui/Buttonrequire('css!../../css/button.css')是不合理的,因为:

  1. package开发时是不可能通过require('css!/src/css/button.css')的。这时候不期望提前了解部署细节,不应该。必然是通过相对id
  2. normalize结果不合理,是relative的。requirejs处理的巧妙,esl也是这么处理的,但是不代表我们就不需要去规避这个问题。

回到最本质的问题:package项目的src目录的目录结构

我们在讨论的,其实是package项目的src目录的目录结构

灰大提出的模式,其他同学为什么不能接受?不能接受的具体原因是什么?

@leeight
Copy link
Member

leeight commented Mar 5, 2013

就这么着吧,我没问题了。

@ecomfe
Copy link
Collaborator Author

ecomfe commented Mar 5, 2013

讨论谢幕

@ecomfe ecomfe closed this as completed Mar 5, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants