-
Notifications
You must be signed in to change notification settings - Fork 12
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
webpack 按需打包加载 #8
Comments
屌屌屌 |
要是三级路由怎么办呢? |
@wefiy 不管是第几级,一直嵌套下去就是了,写法是一样的
|
但是三级路由写了,this.props.children为undefined,导致页面无法渲染,大神求解答 |
@xiaoji201509 你确定是这样子写的吗 <Route path="blog" getComponent={(location, callback) => {
require.ensure([], require => {
callback(null, require('modules/blog'))
}, 'blog')
}}></Route> 注意Route的props是getComponent而不是component,值是一个函数,在函数里面使用 |
|
@xiaoji201509 这么看来代码是没什么问题的,确定做到下面这几点没有
|
本地热加载是出现了这个chunk的,但是就是没执行。也没渲染 |
问题解决了,require('./components/Success')改成这样就可以了require('./components/Success').default, |
你好,我在 webpack.config.js 中定义了 chunkFilename 的命名方式,可是实际生成的 chunkfile 中还是有 id,请问你有遇到过这个问题吗? 我是想生成 我的 react-router 的代码如下: var Movies = function(location, callback) {
require.ensure([], function(require) {
callback(null, require('./movies.jsx'));
}, 'movies');
};
var Movie = function(location, callback) {
require.ensure([], function(require) {
callback(null, require('./movie.jsx'));
}, 'movie');
};
var Books = function(location, callback) {
require.ensure([], function(require) {
callback(null, require('./books.jsx'));
}, 'books');
};
var Book = function(location, callback) {
require.ensure([], function(require) {
callback(null, require('./book.jsx'));
}, 'book');
};
ReactDOM.render((
<Router history={hashHistory}>
<Route path="/" component={App}>
<Route path="movies" getComponent={Movies} />
<Route path="/movie/:id" getComponent={Movie} />
<Route path="books" getComponent={Books} />
<Route path="/book/:id" getComponent={Book} />
</Route>
</Router>
),
document.getElementById('main')
); webpack.config.js 的 output 代码: output: {
path: './dist',
filename: '[name].js',
chuckFilename: '[name].[chunkhash:8].chunk.js',
publicPath: './dist/'
}, 命令行生成的 chunkfile如下: |
@cobish |
@eyasliu 噢原来如此,真是太感谢你了! |
很强!谢谢! |
谢谢 有用 |
呵呵不错。 |
谢谢,很有用🙏 |
在开发过程当中还遇到一个问题: 如果有2个异步加载的页面: require.ensure([], function() {
require('modules/A');
})
require.ensure([], function() {
require('modules/B');
}) 其中 虽然 这样就造成了重复打包的情况。请问遇到这种问题,有什么比较好的方法去解决呢? |
@CommanderXL 你可以在基础包中引用一下 C 包,这样就会将 C 包打进基础包中,在 A 和 B 模块,就不会在将 C 打包进去了。或者像 @cobish 给的 demo 那样也行,专门用一个 entry 来打包需要重复用到的模块,不过这样会多出一个需要手动引入的包,但是这样对于以后的增量升级也是有好处的 |
@CommanderXL 这种方式是可以的,将一些完全跟业务逻辑无关的工具模块打一个包,可以跨项目使用。将有业务逻辑的模块打包成各个小模块按需加载 |
想问下 我按这样写了之后 一切是正常运行的 但是 怎么样 看出项目是按需加载的? |
我发现 我这样写了之后 并没有 按需加载啊。。。是什么情况? |
解决了,自己代码的问题,在路由这里异步加载过,就不需要在其他地方 同步加载了,否则会自动去掉异步的方法 |
webpack.config.js 的 entry 该如何配置呢? |
@FengHaiSheng entry不需要其他特殊配置 |
@eyasliu 非常感谢回答。我照着教程试了,发现确实达到了按需加载的功能。只有一点比较不懂,虽然做了按需加载,但是以前那个文件(所有代码都打包到了这个文件)仍然被加载了(我在network中看到的) |
childRoutes: [{
path: '/welcome',
getComponents: (location, callback) => require.ensure([], require => {callback(null, require("./components/welcome/Welcome.react.jsx").default)},'welcome')
},{
path: '/menu',
getComponents: (location, callback) => require.ensure([], require => {callback(null, require("./components/menu/MenuMain.react").default)},'menu')
},{
path: '/combo/:menuId/:isInclude/:combo_carts/:menu_item',
getComponents: (location, callback) => require.ensure([], require => {callback(null, require("./components/menu/MenuComboMain.react").default)},'combo')
}] 这样配置, 除了'/menu' 剩下的进入对应的路由都有单独的文件生成,唯独 |
@mqliutie 可能是menu里面所有引用的包都在基础包中引用过,所以menu就不需要了 |
@eyasliu 不会的,menu这个组建里面有我自定义的组建,其他文件中没有引入的 |
你好,我有一个项目,entry入口,有8个路由页面,我没有用按需加载的时候直接在index.html里引入bundle.js,bundle.js大小为2.8M。 这样是正常吗? |
@GZWZC 我认为是正常的 我的页面也是这样的 |
这个很详细。 |
注意: 或许有人会想,上面重复代码超级多,能不能用一个函数生成器去生成这些重复的函数呢?代码更进一步优化,比如: const ensureModule = (name, entry) => (location, callback) => { ———————————————— 答案是:不能。这样看起来代码没有任何问题,好像更优雅的样子,但是经过亲自实践后,不行!! |
非常感谢老师的分享,这个帖子给我解开了积压许久的困惑。 |
@CommanderXL 你好,我也遇到了你上述问到的代码分割后多次引入模块(比如echart)重复打包的问题,请问,你这边最后用什么方法处理的? |
css重复问题 怎么处理 |
厉害了 |
666 |
请问一下,我用webpack配置了一个多页面的开发环境,但是我又在一个页面中用路由的形式来配一个路由页面,如果不用懒加载js的话是正常的,但是如果用了懒加载的,发现js没有打包出来。 //首页 |
@yinguangyao 可以用 clean-webpack-plugin 在打包前清楚之前打包的文件重新生成。 |
const ensureModule = (name, entry) => (location, callback) => { 现在函数里包裹 Critical dependency: require function is used in a way in which dependencies cannot be statically extracted |
异步组件a中再异步加载b会怎样,还是打出一个包a还是两个包a和b |
组件库很庞大,但是用到了某些独立的依赖,并且这些依赖随时可以用到,但是又不会经常使用,而且体积也比较大。这种情况没办法使用路由的方式按需加载,必须判断对应的部分是否使用再进行加载。有招吗 |
@SouWinds 新版本的webpack有 import 函数可以做按需加载,你可以这样 // 在需要使用那个组件的时候,才执行import
import('./your/mod').then(() => {
// 组件模块加载完成
}) |
我试试看,我查了下文档,要最小化搜索范围、缩小变量控制区域 |
webpack 懒加载使用 import 引入 js 文件么有生成 chunk 文件 |
为什么需要按需加载
在一个前端应用中,将所有的代码都打包进一个或几个文件中,加载的时候,把所有文件都加载进来,然后执行我们的前端代码。只要我们的应用稍微的复杂一点点,包括依赖后,打包后的文件都是挺大的。而我们加载的时候,不管那些代码有没有执行到,都会下载下来。如果说,我们 只下载我们需要执行的代码的 话,那么可以节省相当大的流量。也就是我们所说的 按需加载
使用 webpack 的按需加载
webpack 官方文档 其实是有介绍的,不过我还是啰嗦的在总结一下
首先我们要看一看一个加载函数
这个方法可以实现js的按需加载,分开打包,webpack 管包叫
chunk
,为了打包能正常输出,我们先给webpack配置文件配置一下chunk文件输出路径这里顺带一提,打包后的js文件基础路径跟普通的资源(图片或字体文件之类)是一样的,就是publicPath, publicPath可以在运行时再去赋值,方法就是在应用入口文件对变量
__webpack_public_path__
进行赋值就行,文档在这每个chunk 都会有一个ID,会在webpack内部生成,当然我们也可以给chunk指定一个名字,就是 require.ensure 的第三个参数
配置文件中
最简单的例子
将会打包出 3 个文件,基础包、chunk1 和 chunk2,但是chunk2在if判断中,而且永远为false,所以 chunk2 虽然打包了但永远不会被加载
结合 react-router 按需加载
如果需要做按需加载,那么这个
需
应该怎样定义呢?我们可以按照前端路由来定义这个需
,在react 应用中,react-router 是一个路由解决方案的第一选择,它本身就有一套动态加载的方案看他们的方法名字就知道他们是干什么的,我也不废话。他们的作用呢,就是在访问到了对应的路由的时候,才会去执行这个函数,如果没有访问到,那么就不会执行。那么我们把加载的函数放在里面就正好合适了,等到访问了该路由的时候,再去执行函数去加载脚本。
根路由
跟路由有点特殊,它一定要先加载一个组件才能渲染,也就是说,在跟路由不能使用按需加载方式,不过这个没关系,根路由用于基础路径,在所有模块都必须加载,所以他的 "需" 其实作用不大。
示例代码
官方有个很简易明了的示例应用, react-router 默认是推荐使用对象去定义路由而不是 jsx,所以这个例子演示了怎么使用 对象的形式定义按需加载模块。
jsx 定义按需加载路由
虽然官方推荐使用对象去定义,但是jsx语法看上去更清晰点,所以还是使用jsx演示,方法很简单,就是把 组件的 props.component 换成 props.getComponent ,函数还是上述例子的函数(记得根路由不要使用getComponent)。
看上去很乱有木有,在jsx中写那么多 js 感觉真难看,把 js 独立出来就是:
这样整理一下,就好看多了
注意: 或许有人会想,上面重复代码超级多,能不能用一个函数生成器去生成这些重复的函数呢?代码更进一步优化,比如:
答案是:不能。这样看起来代码没有任何问题,好像更优雅的样子,但是经过亲自实践后,不行!!因为
require
函数太特别了,他是webpack底层用于加载模块,所以必须明确的声明模块名,require函数在这里只能接受字符串,不能接受变量 。所以还是忍忍算了The text was updated successfully, but these errors were encountered: