fex-team / fis3

FIS3
http://fis.baidu.com
BSD 2-Clause "Simplified" License
2.79k stars 694 forks source link

fis3-postpackager-loader配置的include 文件会产生依赖加载问题 #447

Open fychinesepjj126 opened 8 years ago

fychinesepjj126 commented 8 years ago

这个issue发在插件那边没有人回复,把他拿到fis3这边一起研究。

加载器: mod.js 开发: backbonejs

在backbone中自定义路由module加载函数load,根据modulename,actionname变量名动态进行module的异步加载,主要使用require.async进行异步加载。 对于异步加载,fis会动态分析页面,根据require.async中值生成resourcemap插入到html页面中

当require.async传入的是字符串时,此时生成的resourcemap是可以正常使用的,但如果require.async传入的是变量值,由于fis无法具体分析到模块的路径,因此是无法正常生成resourcemap,对于此种情况,在postpackager-loader中配置include选项可以让resourcemap带上我们所需要的模块。

问题在于: 如果在fis中对include的目录配置了useSameNameRequire=true或者对其中的js配置了相关依赖: 如:

/*
require demo.css
*/

默认会在页面index.html中创建<link .... href="demo.css" />,此时我们并没有使用主动去加载include目录下的任何文件。这里希望在使用require('widgets/demo.js')时是才对相关依赖的css文件进行加载,而不是在初始化时就进行加载。 不知道是我对fis中include变量理解错误,还是加载器在分析过程出现了问题, 对于require.aysnc参数是变量的情况下,我们应当如何处理此种情况?请指教,谢谢!

//backbone路由动态加载module函数
 load: function(target, moduleName, actionName, conditions) {
            ...
            var module_path = target + moduleName + actionName;
            require([module_path], function(cb) {
                if(cb) {
                    cb(param);
                } else {
                    console.error('模块加载失败!');
                }
            });
        }
//fis 相关配置
fis.match('::packager', {
    postpackager: fis.plugin('loader', {
        resourceType: 'mod',
        useInlineMap: false,
        resoucemap: 'static/pkg/${filepath}_map.js',
     include: [
          'widgets/**.js' 
        ]
    }),
    packager: fis.plugin('map')
})
2betop commented 8 years ago

是这样的,loader 并没有异步加载 css, 当分析到异步 css 的时候, loader 其实是把他当同步处理,提前加载的。主要原因是 mod.js 还不能很好的处理 css 资源。

但是,我觉得你可以考虑把 css 当 js 来加载,配置这个插件。

https://github.com/fex-team/fis3-preprocessor-css2js

require.async('./widget/demo.css');

2betop commented 8 years ago

ps: 把插件中的 issue 关了吧,就在这讨论。

oxUnd commented 8 years ago

@2betop 并不是 mod 不能很好处理异步的 css,而是我们不会这么做,因为 css 异步会闪屏幕。如果不想闪屏还想做 css 异步加载,那么模板也得做异步加载或者做隐藏处理。这就是另外一会事情了。

fychinesepjj126 commented 8 years ago

@2betop 你是建议把js中css相关依赖设定删除,加上require.async('./widget/demo.css');手动去控制css加载么? 这或许是避免css被同步加载的一种方法。

多谢@2betop @xiangshouding 两位的回答!我大概理解了问题所在。

总结下: 在正常情况下,module不进行动态加载时(require / require.async参数不是变量情况下),在分析useSameNameRequire=true相关目录时loader总是先把css文件预先生成到html中, 由于backbone 中module是动态加载,对于插件loader无法在编译时获取相关module加载路径,为了使modjs require正常运行,配置了include参数,保证了resourcemap正常生成。此时loader为了保证css能提前加载,依然同步生成了css加载路径,也就产生了本文所说的 问题。

当前理想情况下,我们还是希望require在加载js同时,再对css文件进行同步加载。loader这种预先加载方式会导致widgets目录中所有相关css文件都一并加载了,绝大部分情况下,使用backbone的动态加载module的功能就是为了减少不必要的加载。

2betop commented 8 years ago

不是一定得 require.async, 在 module 里面你也可以 require('./demo.css'), 这样,你的 module 被异步加载的时候,自动就把 css 给加载了。且会在你的代码执行之前把样式写入dom, 比较符合你的预期。

2betop commented 8 years ago

@xiangshouding 先下载 css ,等 css 下载完了后再去加载 js 就不会闪烁了。yog 里面的 bigpipe 就是这么做的。

oxUnd commented 8 years ago

那 html 呢,这个是两回事儿,bigpipe 不也就叫 bigpipe 方案吗?跟 mod 是否支持此类没啥关系,mod 有它自己的使命,并不需要去关心别的。

sojuker commented 8 years ago

看上去,mod 只做 js-module-loader。所以方案是 css —> css transform to js module

静态依赖分析肯定不能完全解决动态加载问题,只能通过冗余来解决这类问题。 要么是 require 出所有可能的依赖,在加载资源上做冗余。 要么是 require.async + resoureMap 的冗余。

css 何时载入? 以 fisp 之类的服务端模板渲染解决方案(业务模式)来看,同步加载css更加好,也能快速实施。基于单页面应用场景(业务模式)而言,异步加载CSS肯定是最主要场景,虽然可以用 fis3 插件做 css transform js module,但不知这样处理是否优雅(没有完全看懂 preprocessor-css2js 的源码,但感觉不太优雅)。

很想了解下之前 fis 支持的单页面应用,css 的异步加载是采用什么方案来处理? 个人理解应该还是通过增强 loader 加载 css 能力的方式居多吧。此外,个人感觉 mv* 类的单页面应用似乎是未来趋势(并不是说 fisp 这一类服务端静态资源管理方案会被淘汰,应该会变成一种非主流方案),fis 在这方面最中意的解决方案不知有没有?

最近看 webpack,我觉得它的思想或许不太成熟,但思路比较新颖。 fis3 的核心思想是解决资源管理问题,并基于此搭建的一套流程体系,这点非常明确。但在流程设计上,似乎有些老旧和不太清晰(或许是文档的问题,我对fis3编译流程的细节一直不太理解)。 随便说说想法,no bad feeling。

fychinesepjj126 commented 8 years ago

@sojuker 在使用fis前也对比了webpack,总体感觉fis在资源管理这块还是比较优秀的,毕竟是国产的工具,在文档方面还是亲切很多,虽然在某些方面(如异步加载css)有些让人琢磨不透。文档方面还是要继续完善,有更多的人使用,才能让fis更加的强大。

准备抽时间在研究下webpack,看看webpack是否可以和fis一起使用,相互补充,发挥它们最大特点。 如果有谁更加了解webpack原理也可以在这里讨论下。

a526672351 commented 7 years ago

@xiangshouding @2betop 我还有一种情景更复杂的是,一个弹窗ajax加载html页面,而这个html页面aio后的CSS 无法提前打包,也无法异步加载,有没有解决方案 #1131