我假设我可以实现我想用webpack做的事情,但仍然无法弄明白.这是用例.
我有几个Angular应用程序(将在相同的浏览器窗口中加载),它将重用完全相同的供应商包.目前webpack在每个应用程序中生成两个文件app.[app_module_name] .js和vendor.js.所以理论上我应该只能在html页面中包含一个vendor.js文件,然后加载几个app模块.但是这不起作用,因为供应商中lib的webpack内部引用彼此不同.
以下是我目前的配置.如果有人可以帮助我,那会很棒.
entry: {
bootstrap: './src/app/init/bootstrap.js',
tradingApp: './src/app/app.js'
},
output: {
filename: '[name].bundle.js',
publicPath: '/',
path: path.join(projectRoot, 'dist')
},
plugins:[
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module) {
return module.resource && module.resource.indexOf(path.join(projectRoot, 'src')) === -1
}
}),
]
Run Code Online (Sandbox Code Playgroud) 我正在尝试使用react-loadable将代码拆分到我的应用程序中.我在一个非常简单的组件上尝试了它:
const LoadableComponent = Loadable({
loader: () => import('components/Shared/Logo/Logo'),
loading: <div>loading</div>,
});
Run Code Online (Sandbox Code Playgroud)
但是,当呈现此组件时,我收到以下错误:
Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object.
Check the render method of `LoadableComponent`.
in LoadableComponent (created by AppHeader)
in div (created by AppHeader)
in AppHeader (created by PlainChatApp)
in div (created by PlainChatApp)
in PlainChatApp (created by DragDropContext(PlainChatApp))
in DragDropContext(PlainChatApp) (created by Connect(DragDropContext(PlainChatApp)))
in Connect(DragDropContext(PlainChatApp))
in Provider
in AppContainer
in ErrorBoundary
The above …Run Code Online (Sandbox Code Playgroud) 我们使用带有React的webpack 1.x捆绑我们的应用程序.此外,为了在javascript文件发生变化时破坏缓存,我们将输出设置webpack.config.js为:
output: {
path: __dirname + '/dist',
filename: 'index_bundle.[chunkhash:10].js',
publicPath: '/'
},
Run Code Online (Sandbox Code Playgroud)
这成功地实现了我们在部署新版本应用程序时更改文件名的目标.在成功部署后,可以看到新文件存在.
当用户在部署期间在应用程序上时,会出现皱纹.突然之间,曾经存在的块没有,并且当index.html成功更新时,浏览器当前正在使用的一些块会对旧的,不存在的文件产生错误请求.
webpack是否有传统的方式来处理交换机?或者在我们的React应用程序中,让它优雅地处理错误的组件导入.我们主持S3,它(就像Meteor,我的印象)在一个不存在的文件请求上回退到index.html.在我们的应用程序中,这会导致Syntax error: Unexpected token <错误,因为它需要javascript而不是HTML.
编辑:为了避免我的React应用程序中的错误导入,也许我可以在路由的index.js文件中应用逻辑?目前我的getComponent调用看起来像这样:
getComponent(nextState, callback) {
require.ensure([], (require) => {
callback(null, require('./components/HomePage').default);
});
}
Run Code Online (Sandbox Code Playgroud)
编辑2: 在这里找到我的问题的答案.
我们正在开发一个 React 组件库。某些组件需要更新,而无需重新部署主机应用程序代码。这非常类似于 Google 地图库,其中客户端 API 是一个小型 shell 代码,它在运行时导入实际的地图代码,从而允许热更新而无需任何主机停机。所以我们计划将该库的输出分成两部分 -
Shell 组件库,任何主机应用程序代码都将使用它来导入 shell 组件。例如
import Notifications from 'our-shell-lib';
render(){
return <Notifications .../>;
}
Run Code Online (Sandbox Code Playgroud)在上面的示例中,Notifications 组件将从我们的服务器下载NotificationsCore 组件并在内部安装它。
我们已经能够导出单个 shell 组件,并且它使用此处描述的基于scriptjs 的技术在运行时正确下载相应的核心组件。
然而,当核心组件使用动态导入时,就会中断,从而导致代码分割。所有核心组件文件都可以在远程服务器上使用,但我们尚未成功地将它们打包为具有动态导入的核心组件可以以与服务器 URL 无关的方式从远程服务器加载其分割块。我们不想在核心包中硬编码公共路径。我们可以在运行时将服务器路径传递给核心组件,以帮助它找到动态导入,但目前还没有找到方法。
想法?
我有以下webpack配置:
const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
source1: './frontend/source1.js',
source2: './frontend/source2.js'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'static/bundles')
},
plugins: [
new CleanWebpackPlugin(['static/bundles'])
],
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader', // ??? .vue-??????
options: {
loaders: {
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
}
]
},
resolve: {
alias: {
vue$: 'vue/dist/vue.esm.js'
}
}
}; …Run Code Online (Sandbox Code Playgroud) 我理解在webpack上完成的伟大工作4.特别是重写代码拆分插件.但是,由于它仍然有点新,我没有找到关于新SplitChunksPlugin的好文档.
我在选择的术语的含义上挣扎.例如:
块:有3个可能的值"initial","async"和"all".这是什么意思?初始块是条目?异步动态导入?一切都是初始+异步?如果我使用initial,那么我的动态导入块将无法利用代码拆分?例如.main.tsx动态导入about.tsx,它正常导入lodash.Lodash不会被提取到供应商捆绑?
强制执行:我看到很多配置设置强制执行:true,这是什么意思?
为了更好的上下文,我发布了一个splitChunks配置的例子.
optimization: {
splitChunks: {
cacheGroups: {
'commons': {
minChunks: 2,
chunks: 'all',
name: 'commons',
priority: 10,
enforce: true,
},
},
},
},Run Code Online (Sandbox Code Playgroud)
例如,假设我们有两个具有共同导入的组件:
...
import Hello from './Hello'
class A extends Component {}
Run Code Online (Sandbox Code Playgroud)
和
...
import Hello from './Hello'
class B extends Component {}
Run Code Online (Sandbox Code Playgroud)
然后这些组件会异步加载到另一个组件中,如下所示:
...
import Loadable from 'react-loadable'
const AsyncA = Loadable({
loader: () => import(/* webpackChunkName: "A" */ "./A"),
loading: () => <div>Generic Loading Message</div>
});
const AsyncB = Loadable({
loader: () => import(/* webpackChunkName: "B" */ "./B"),
loading: () => <div>Generic Loading Message</div>
});
Run Code Online (Sandbox Code Playgroud)
“A”和“B”块都将包含“Hello”代码,将重复的代码传送到浏览器。
在我的研究中,我确定如果在任何其他未异步加载的组件中导入“Hello”,则不会发生这种情况。在这种情况下,它被捆绑到“主”块中,而不是“A”和“B”块中。
虽然这是一种选择,但仍有很多不足之处。本指南演示了如何配置 webpack 以创建一个“通用”模块,这看起来很理想,因为它不需要任何代码重构即可达到预期效果。
但是,webpack 配置不受 CRA 限制。
这里有更好的解决方案吗?
我正在使用create-react-app。我想要反应路由器基本代码分割,但我想获取用户在浏览器中打开的第一个块,然后在后台异步获取其他块
路线
const HomeModule = React.lazy(() => import('./modules/ft_home_module/src/main'));
const AuthModule = React.lazy(() => import('./modules/ft_auth_module/src/main'));
const ProfileModule = React.lazy(() => import('./modules/ft_profile_module/src/main'));
const MerchantModule = React.lazy(() => import('./modules/ft_merchant_module/src/main'));
<Route path="/home" component={HomeModule} />
<Route path="/auth" component={AuthModule} />
<Route path="/profile" component={ProfileModule} />
<Route path="/merchant" component={MerchantModule} />
Run Code Online (Sandbox Code Playgroud)
假设,如果用户在浏览器中打开 /home,则在加载第一个块之后将首先加载 home 块,并在后台异步调用其他块
所需输出
/home在浏览器中打开实际上我正在通过lighthouse chrome 扩展测试性能。路由器基本代码分割为我提供了第一页的良好性能,但是当我打开第二页时,它需要时间,但不应该花费时间。我认为如果我们在加载第一个块后在后台异步获取其他块,这是可能的
reactjs code-splitting create-react-app react-router-dom code-splitting-async
假设我有 3 个由动态导入创建的异步块:
const Notes = lazy(() => import(/* webpackChunkName: "notes" */ 'pages/Notes'))
const Lists = lazy(() => import(/* webpackChunkName: "lists" */ 'pages/Lists'))
const Files = lazy(() => import(/* webpackChunkName: "files" */ 'pages/Files'))
Run Code Online (Sandbox Code Playgroud)
将生成:
notes.g3g43g.js
lists.534535.js
files.234f8t.js
Run Code Online (Sandbox Code Playgroud)
每个块都包含它自己的供应商依赖项。
所以在notes.g3g43g.js里面我们有react-big-calendar和lodash。
但是,当使用 SplitChunksPlugin 时,我们可以将chunks选项设置为all:
optimization: {
runtimeChunk: 'single',
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: ({ context }) => (context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1]
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
从这一点来看,react-big-calendar和lodash …
javascript webpack code-splitting html-webpack-plugin splitchunksplugin
code-splitting ×10
webpack ×7
javascript ×4
reactjs ×4
angularjs ×1
react-router ×1
webpack-2 ×1
webpack-4 ×1