[WIP] new tools

This commit is contained in:
Piotr Janosz
2019-08-13 15:03:51 +02:00
committed by fabioberger
parent ffdb5c06f6
commit fdbc235fd6
13 changed files with 219 additions and 172 deletions

View File

@@ -1,6 +1,6 @@
> # Class: AssetBuyer
# AssetBuyer
## Hierarchy
<!-- ## Hierarchy
* **AssetBuyer**
@@ -27,11 +27,11 @@
* [getLiquidityForAssetDataAsync](#getliquidityforassetdataasync)
* [getOrdersAndFillableAmountsAsync](#getordersandfillableamountsasync)
* [getAssetBuyerForProvidedOrders](#static-getassetbuyerforprovidedorders)
* [getAssetBuyerForStandardRelayerAPIUrl](#static-getassetbuyerforstandardrelayerapiurl)
* [getAssetBuyerForStandardRelayerAPIUrl](#static-getassetbuyerforstandardrelayerapiurl) -->
## Constructors
### constructor
Constructor
\+ **new AssetBuyer**(`supportedProvider`: `SupportedProvider`, `orderProvider`: [OrderProvider](#class-assetbuyer)*
@@ -55,7 +55,7 @@ An instance of AssetBuyer
### expiryBufferSeconds
• **expiryBufferSeconds**: *number*
`expiryBufferSeconds: number`
*Defined in [asset_buyer.ts:41](https://github.com/0xProject/0x-monorepo/blob/6dd77d5c8/packages/asset-buyer/src/asset_buyer.ts#L41)*
@@ -259,7 +259,7 @@ An instance of AssetBuyer
<hr />
> # Class: InsufficientAssetLiquidityError
# Class: InsufficientAssetLiquidityError
Error class representing insufficient asset liquidity
@@ -351,7 +351,7 @@ Defined in /Users/rickmorty/Documents/projects/0x/0x-monorepo/node_modules/typed
<hr />
> # Class: BasicOrderProvider
# Class: BasicOrderProvider
## Hierarchy
@@ -446,7 +446,7 @@ An instance of OrderProviderResponse. See type for more information.
<hr />
> # Class: StandardRelayerAPIOrderProvider
# Class: StandardRelayerAPIOrderProvider
## Hierarchy
@@ -551,7 +551,7 @@ An instance of OrderProviderResponse. See type for more information.
<hr />
> # Enumeration: AssetBuyerError
# Enumeration: AssetBuyerError
Possible error messages thrown by an AssetBuyer instance or associated static methods.
@@ -652,7 +652,7 @@ ___
<hr />
> # Interface: AssetBuyerOpts
# Interface: AssetBuyerOpts
networkId: The ethereum network id. Defaults to 1 (mainnet).
orderRefreshIntervalMs: The interval in ms that getBuyQuoteAsync should trigger an refresh of orders and order states. Defaults to 10000ms (10s).
@@ -696,7 +696,7 @@ ___
<hr />
> # Interface: BuyQuote
# Interface: BuyQuote
assetData: String that represents a specific asset (for more info: https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
assetBuyAmount: The amount of asset to buy.
@@ -780,7 +780,7 @@ ___
<hr />
> # Interface: BuyQuoteExecutionOpts
# Interface: BuyQuoteExecutionOpts
ethAmount: The desired amount of eth to spend. Defaults to buyQuote.worstCaseQuoteInfo.totalEthAmount.
takerAddress: The address to perform the buy. Defaults to the first available address from the provider.
@@ -844,7 +844,7 @@ ___
<hr />
> # Interface: BuyQuoteInfo
# Interface: BuyQuoteInfo
assetEthAmount: The amount of eth required to pay for the requested asset.
feeEthAmount: The amount of eth required to pay the affiliate fee.
@@ -888,7 +888,7 @@ ___
<hr />
> # Interface: BuyQuoteRequestOpts
# Interface: BuyQuoteRequestOpts
feePercentage: The affiliate fee percentage. Defaults to 0.
shouldForceOrderRefresh: If set to true, new orders and state will be fetched instead of waiting for the next orderRefreshIntervalMs. Defaults to false.
@@ -932,7 +932,7 @@ ___
<hr />
> # Interface: LiquidityForAssetData
# Interface: LiquidityForAssetData
Represents available liquidity for a given assetData
@@ -965,7 +965,7 @@ ___
<hr />
> # Interface: OrderProvider
# Interface: OrderProvider
gerOrdersAsync: Given an OrderProviderRequest, get an OrderProviderResponse.
getAvailableMakerAssetDatasAsync: Given a taker asset data string, return all availabled paired maker asset data strings.
@@ -1024,7 +1024,7 @@ Name | Type |
<hr />
> # Interface: OrderProviderRequest
# Interface: OrderProviderRequest
makerAssetData: The assetData representing the desired makerAsset.
takerAssetData: The assetData representing the desired takerAsset.
@@ -1059,7 +1059,7 @@ ___
<hr />
> # Interface: OrderProviderResponse
# Interface: OrderProviderResponse
orders: An array of orders with optional remaining fillable makerAsset amounts. See type for more info.
@@ -1083,7 +1083,7 @@ orders: An array of orders with optional remaining fillable makerAsset amounts.
<hr />
> # Interface: OrdersAndFillableAmounts
# Interface: OrdersAndFillableAmounts
orders: An array of signed orders
remainingFillableMakerAssetAmounts: A list of fillable amounts for the signed orders. The index of an item in the array associates the amount with the corresponding order.
@@ -1117,7 +1117,7 @@ ___
<hr />
> # Interface: SignedOrderWithRemainingFillableMakerAssetAmount
# Interface: SignedOrderWithRemainingFillableMakerAssetAmount
A normal SignedOrder with one extra optional property `remainingFillableMakerAssetAmount`
remainingFillableMakerAssetAmount: The amount of the makerAsset that is available to be filled

View File

@@ -55,12 +55,17 @@ const Wrapper = styled.div`
`;
const Container = styled.div`
border: 1px solid ${colors.brandDark};
border: 1px solid #e3e3e3;
border-radius: 4px;
display: inline-block;
margin-left: 12px;
position: relative;
transition: all 250ms ease-in-out;
&:hover {
border-color: ${colors.brandDark};
}
svg {
pointer-events: none;
position: absolute;
@@ -72,7 +77,7 @@ const Container = styled.div`
const StyledSelect = styled.select`
appearance: none;
background-color: #fff;
background-color: transparent;
border: none;
cursor: pointer;
outline: none;

View File

@@ -4,6 +4,7 @@ import styled from 'styled-components';
import { Collapse } from 'ts/components/docs/sidebar/collapse';
import { colors } from 'ts/style/colors';
import { docs } from 'ts/style/docs';
interface ISidebarWrapperProps {
@@ -31,9 +32,22 @@ const SidebarAside = styled.aside`
const SidebarContent = styled.div`
position: sticky;
top: ${docs.headerOffset}px; /* To make space for the header (react-headroom) when clicking on links */
max-height: 60vh;
max-height: 85vh;
overflow-y: auto;
/* Slim scroll bar */
scrollbar-color: ${colors.grey500};
scrollbar-width: 1px; /* Firefox */
-ms-overflow-style: none; /* IE 10+ */
&::-webkit-scrollbar {
height: 1px;
width: 1px;
background: transparent; /* Chrome / Safari / Webkit */
}
&::-webkit-scrollbar-thumb {
background-color: ${colors.grey350};
}
@media (max-width: 900px) {
max-height: 100%;
}

View File

@@ -8,6 +8,8 @@ import { docs } from 'ts/style/docs';
import { SidebarWrapper } from 'ts/components/docs/sidebar/sidebar_wrapper';
import { Select } from 'ts/components/docs/sidebar/select';
interface ITableOfContentsProps {
contents: IContents[];
}
@@ -19,9 +21,35 @@ export interface IContents {
title: string;
}
export interface ISelectItemConfig {
label: string;
value?: string;
onClick?: () => void;
}
const items: ISelectItemConfig[] = [
{
label: 'v6.1.10',
onClick: () => {
console.log('YEAH 10');
},
},
{
label: 'v6.1.11',
onClick: () => {
console.log('YEAH 11');
},
},
];
const onChange = () => {
console.log('ON CHANGE!');
};
export const TableOfContents: React.FC<ITableOfContentsProps> = ({ contents }) => {
return (
<SidebarWrapper>
<Select emptyText="6.1.11" id="select-versions" items={items} value="6.1.11" onChange={onChange} />
<Contents contents={contents} />
</SidebarWrapper>
);
@@ -63,19 +91,26 @@ const ContentLink = styled(Link)<{ level: number }>`
display: inline-block;
span {
color: ${colors.textDarkSecondary};
color: #999;
font-weight: 300;
transition: all 250ms ease-in-out;
}
&:hover span,
&.active span {
color: ${colors.brandDark};
}
&.active span {
font-weight: 500;
}
${({ level }) =>
level === 1 &&
`
font-size: 0.8333rem;
margin-bottom: 1rem;
line-height: 1.5;
margin-bottom: .5rem;
`}
@@ -83,10 +118,12 @@ const ContentLink = styled(Link)<{ level: number }>`
level === 2 &&
`
font-size: 0.7222rem;
line-height: 1.45;
padding: 0.25rem 0 0.25rem 0.7rem;
line-height: 2;
padding-left: 0.7rem;
border-left: 1px solid #e3e3e3;
transition: all 250ms ease-in-out;
&:hover,
&.active {
border-color: ${colors.brandDark};
}

View File

@@ -24,6 +24,7 @@ interface HeadingProps extends BaseTextInterface {
interface ParagraphProps extends BaseTextInterface {
isNoMargin?: boolean;
lineHeight?: number | string;
marginBottom?: string; // maybe we should remove isNoMargin
isMuted?: boolean | number;
fontWeight?: string | number;
@@ -71,9 +72,10 @@ export const Paragraph = styled.p<ParagraphProps>`
color: ${props => props.color || props.theme.paragraphColor};
opacity: ${props => (typeof props.isMuted === 'boolean' ? 0.75 : props.isMuted)};
text-align: ${props => (props.textAlign ? props.textAlign : props.isCentered && 'center')};
line-height: 1.4;
line-height: ${props => props.lineHeight};
`;
Paragraph.defaultProps = {
isMuted: true,
lineHeight: 1.4,
};

View File

@@ -109,139 +109,121 @@ render(
<>
<MetaTags title={DOCUMENT_TITLE} description={DOCUMENT_DESCRIPTION} />
<Router>
<MuiThemeProvider muiTheme={muiTheme}>
<Provider store={store}>
<Switch>
{/* Next (new site) routes */}
<Route exact={true} path="/" component={NextLanding as any} />
<Route exact={true} path={WebsitePaths.Why} component={NextWhy as any} />
<Route
exact={true}
path={WebsitePaths.MarketMaker}
component={NextMarketMaker as any}
/>
<Route exact={true} path={WebsitePaths.Explore} component={Explore as any} />
<Route exact={true} path={WebsitePaths.Credits} component={Credits as any} />
<Route exact={true} path={WebsitePaths.Instant} component={Next0xInstant as any} />
<Route exact={true} path={WebsitePaths.LaunchKit} component={NextLaunchKit as any} />
<Route exact={true} path={WebsitePaths.Ecosystem} component={NextEcosystem as any} />
<Route exact={true} path={`${WebsitePaths.Vote}/:zeip`} component={Governance as any} />
<Route exact={true} path={WebsitePaths.Vote} component={VoteIndex as any} />
<Route exact={true} path={WebsitePaths.Extensions} component={Extensions as any} />
<Route exact={true} path={WebsitePaths.AssetSwapperPage} component={CFL as any} />
<Route
exact={true}
path={WebsitePaths.PrivacyPolicy}
component={PrivacyPolicy as any}
/>
<Route
exact={true}
path={WebsitePaths.TermsOfService}
component={TermsOfService as any}
/>
<Route
exact={true}
path={WebsitePaths.AboutMission}
component={NextAboutMission as any}
/>
<Route exact={true} path={WebsitePaths.AboutTeam} component={NextAboutTeam as any} />
<Route exact={true} path={WebsitePaths.AboutPress} component={NextAboutPress as any} />
<Route exact={true} path={WebsitePaths.AboutJobs} component={NextAboutJobs as any} />
{/*
<MuiThemeProvider muiTheme={muiTheme}>
<Provider store={store}>
<Switch>
{/* Next (new site) routes */}
<Route exact={true} path="/" component={NextLanding as any} />
<Route exact={true} path={WebsitePaths.Why} component={NextWhy as any} />
<Route exact={true} path={WebsitePaths.MarketMaker} component={NextMarketMaker as any} />
<Route exact={true} path={WebsitePaths.Explore} component={Explore as any} />
<Route exact={true} path={WebsitePaths.Credits} component={Credits as any} />
<Route exact={true} path={WebsitePaths.Instant} component={Next0xInstant as any} />
<Route exact={true} path={WebsitePaths.LaunchKit} component={NextLaunchKit as any} />
<Route exact={true} path={WebsitePaths.Ecosystem} component={NextEcosystem as any} />
<Route exact={true} path={`${WebsitePaths.Vote}/:zeip`} component={Governance as any} />
<Route exact={true} path={WebsitePaths.Vote} component={VoteIndex as any} />
<Route exact={true} path={WebsitePaths.Extensions} component={Extensions as any} />
<Route exact={true} path={WebsitePaths.AssetSwapperPage} component={CFL as any} />
<Route
exact={true}
path={WebsitePaths.PrivacyPolicy}
component={PrivacyPolicy as any}
/>
<Route
exact={true}
path={WebsitePaths.TermsOfService}
component={TermsOfService as any}
/>
<Route exact={true} path={WebsitePaths.AboutMission} component={NextAboutMission as any} />
<Route exact={true} path={WebsitePaths.AboutTeam} component={NextAboutTeam as any} />
<Route exact={true} path={WebsitePaths.AboutPress} component={NextAboutPress as any} />
<Route exact={true} path={WebsitePaths.AboutJobs} component={NextAboutJobs as any} />
{/*
Note(ez): We remove/replace all old routes with next routes
once we're ready to put a ring on it. for now let's keep em there for reference
*/}
<Redirect from="/otc" to={`${WebsitePaths.Portal}`} />
<Route path={WebsitePaths.Portal} component={LazyPortal} />
<Route path={WebsitePaths.Wiki} component={Wiki as any} />
<Route
path={`${WebsitePaths.ZeroExJs}/:version?`}
component={LazyZeroExJSDocumentation}
/>
<Route
path={`${WebsitePaths.ContractWrappers}/:version?`}
component={LazyContractWrappersDocumentation}
/>
<Route
path={`${WebsitePaths.Migrations}/:version?`}
component={LazyMigrationsDocumentation}
/>
<Route
path={`${WebsitePaths.Connect}/:version?`}
component={LazyConnectDocumentation}
/>
<Route
path={`${WebsitePaths.SolCompiler}/:version?`}
component={LazySolCompilerDocumentation}
/>
<Route
path={`${WebsitePaths.SolCoverage}/:version?`}
component={LazySolCoverageDocumentation}
/>
<Route
path={`${WebsitePaths.SolTrace}/:version?`}
component={LazySolTraceDocumentation}
/>
<Route
path={`${WebsitePaths.SolProfiler}/:version?`}
component={LazySolProfilerDocumentation}
/>
<Route
path={`${WebsitePaths.JSONSchemas}/:version?`}
component={LazyJSONSchemasDocumentation}
/>
<Route
path={`${WebsitePaths.Subproviders}/:version?`}
component={LazySubprovidersDocumentation}
/>
<Route
path={`${WebsitePaths.OrderUtils}/:version?`}
component={LazyOrderUtilsDocumentation}
/>
<Route
path={`${WebsitePaths.Web3Wrapper}/:version?`}
component={LazyWeb3WrapperDocumentation}
/>
<Route
path={`${WebsitePaths.SmartContracts}/:version?`}
component={LazySmartContractsDocumentation}
/>
<Route
path={`${WebsitePaths.EthereumTypes}/:version?`}
component={LazyEthereumTypesDocumentation}
/>
<Route
path={`${WebsitePaths.AssetBuyer}/:version?`}
component={LazyAssetBuyerDocumentation}
/>
<Route
path={`${WebsitePaths.AssetSwapperDocs}/:version?`}
component={LazyAssetSwapperDocumentation}
/>
<Route path={`${WebsitePaths.Docs}/:type/:page`} component={DocsPage as any} />
<Route exact={true} path={WebsitePaths.DocsCoreConcepts} component={DocsPage as any} />
<Route exact={true} path={WebsitePaths.DocsGuides} component={DocsGuides as any} />
<Route exact={true} path={WebsitePaths.DocsTools} component={DocsTools as any} />
<Route exact={true} path={WebsitePaths.Docs} component={DocsHome as any} />
{/* Legacy endpoints */}
<Route
path={`${WebsiteLegacyPaths.ZeroExJs}/:version?`}
component={LazyZeroExJSDocumentation}
/>
<Route
path={`${WebsiteLegacyPaths.Web3Wrapper}/:version?`}
component={LazyWeb3WrapperDocumentation}
/>
<Route
path={`${WebsiteLegacyPaths.Deployer}/:version?`}
component={LazySolCompilerDocumentation}
/>
<Redirect from={WebsiteLegacyPaths.Jobs} to={WebsitePaths.AboutJobs} />
<Redirect from={WebsitePaths.Careers} to={WebsitePaths.AboutJobs} />
<Route component={NotFound as any} />
</Switch>
</Provider>
</MuiThemeProvider>
<Redirect from="/otc" to={`${WebsitePaths.Portal}`} />
<Route path={WebsitePaths.Portal} component={LazyPortal} />
<Route path={WebsitePaths.FAQ} component={FAQ as any} />
<Route path={WebsitePaths.Wiki} component={Wiki as any} />
<Route path={`${WebsitePaths.ZeroExJs}/:version?`} component={LazyZeroExJSDocumentation} />
<Route
path={`${WebsitePaths.ContractWrappers}/:version?`}
component={LazyContractWrappersDocumentation}
/>
<Route path={`${WebsitePaths.Migrations}/:version?`} component={LazyMigrationsDocumentation} />
<Route
path={`${WebsitePaths.OrderWatcher}/:version?`}
component={LazyOrderWatcherDocumentation}
/>
<Route path={`${WebsitePaths.Connect}/:version?`} component={LazyConnectDocumentation} />
<Route
path={`${WebsitePaths.SolCompiler}/:version?`}
component={LazySolCompilerDocumentation}
/>
<Route
path={`${WebsitePaths.SolCoverage}/:version?`}
component={LazySolCoverageDocumentation}
/>
<Route path={`${WebsitePaths.SolTrace}/:version?`} component={LazySolTraceDocumentation} />
<Route
path={`${WebsitePaths.SolProfiler}/:version?`}
component={LazySolProfilerDocumentation}
/>
<Route
path={`${WebsitePaths.JSONSchemas}/:version?`}
component={LazyJSONSchemasDocumentation}
/>
<Route
path={`${WebsitePaths.Subproviders}/:version?`}
component={LazySubprovidersDocumentation}
/>
<Route path={`${WebsitePaths.OrderUtils}/:version?`} component={LazyOrderUtilsDocumentation} />
<Route
path={`${WebsitePaths.Web3Wrapper}/:version?`}
component={LazyWeb3WrapperDocumentation}
/>
<Route
path={`${WebsitePaths.SmartContracts}/:version?`}
component={LazySmartContractsDocumentation}
/>
<Route
path={`${WebsitePaths.EthereumTypes}/:version?`}
component={LazyEthereumTypesDocumentation}
/>
<Route
path={`${WebsitePaths.AssetBuyer}/:version?`}
component={LazyAssetBuyerDocumentation}
/>
<Route
path={`${WebsitePaths.AssetSwapperDocs}/:version?`}
component={LazyAssetSwapperDocumentation}
/>
<Route exact={true} path={WebsitePaths.Docs} component={DocsHome as any} />
<Route exact={true} path={WebsitePaths.DocsGuides} component={DocsGuides as any} />
<Route exact={true} path={WebsitePaths.DocsTools} component={DocsTools as any} />
<Route path={`${WebsitePaths.Docs}/:type/:page?/:version?`} component={DocsPage as any} />
{/* Legacy endpoints */}
<Route
path={`${WebsiteLegacyPaths.ZeroExJs}/:version?`}
component={LazyZeroExJSDocumentation}
/>
<Route
path={`${WebsiteLegacyPaths.Web3Wrapper}/:version?`}
component={LazyWeb3WrapperDocumentation}
/>
<Route
path={`${WebsiteLegacyPaths.Deployer}/:version?`}
component={LazySolCompilerDocumentation}
/>
<Redirect from={WebsiteLegacyPaths.Jobs} to={WebsitePaths.AboutJobs} />
<Redirect from={WebsitePaths.Careers} to={WebsitePaths.AboutJobs} />
<Route component={NotFound as any} />
</Switch>
</Provider>
</MuiThemeProvider>
</Router>
</>,
document.getElementById('app'),

View File

@@ -49,19 +49,20 @@ export const DocsPage: React.FC<IDocsPageProps> = props => {
const { Component, contents, wasNotFound } = state;
const isLoading = !Component && !wasNotFound;
const { page, type } = props.match.params;
const { page, type, version } = props.match.params;
const { hash } = props.location;
// For api explorer / core-concepts the url does not include the page, i.e. it's only 'docs/core-concepts'
const key = page ? page : type;
const { subtitle, title } = meta[page];
const { path, subtitle, title, versions } = meta[key];
React.useEffect(() => {
void loadPageAsync(page, type);
}, [page, type]);
void loadPageAsync(path);
}, [path]);
const loadPageAsync = async (fileName: string, dirName: string) => {
const loadPageAsync = async (path: string) => {
try {
const component = await import(`../../../mdx/${dirName}/${fileName}.mdx`);
// const component = await import(`../../../mdx/tools/@0x/asset-buyer/v6.1.11/reference.mdx`);
const component = await import(`mdx/${path}`);
setState({
...state,
@@ -125,7 +126,7 @@ export const DocsPage: React.FC<IDocsPageProps> = props => {
</MDXProvider>
<NewsletterWidget />
<HelpCallout />
<HelpfulCta page={page} />
<HelpfulCta page={key} />
</ContentWrapper>
</Columns>
)}

View File

@@ -1,5 +1,5 @@
export const docs = {
scrollDuration: 500,
scrollDuration: 0,
headerOffset: 116,
marginBottom: '1.875rem',
};

View File

@@ -433,8 +433,8 @@ export enum WebsitePaths {
Portal = '/portal',
Wiki = '/wiki',
Docs = '/docs',
DocsApiExplorer = '/docs/api-explorer/index',
DocsCoreConcepts = '/docs/core-concepts/core-concepts',
DocsApiExplorer = '/docs/api-explorer',
DocsCoreConcepts = '/docs/core-concepts',
DocsGuides = '/docs/guides',
DocsTools = '/docs/tools',
ZeroExJs = '/docs/0x.js',

View File

@@ -1,13 +1,15 @@
// @TODO: Fix all descriptions!
export const meta: { [key: string]: any } = {
// Api explorer
'api-explorer': {
title: '0x API Explorer',
// @TODO: adjust api explorer meta here
path: 'api-explorer/index.mdx',
},
// Core concepts
'core-concepts': {
title: '0x Core Concepts',
subtitle: "Learn all the core concepts you'll need to build effectively on 0x",
path: 'core-concepts/index.mdx',
},
// Guides
'build-a-relayer': {
@@ -16,6 +18,7 @@ export const meta: { [key: string]: any } = {
tags: ['Relayer', 'Trader', 'Protocol Developer'],
topics: ['Coordinator Model', 'Mesh'],
difficulty: 'Advanced',
path: 'guides/build-a-relayer.mdx',
},
'develop-on-ethereum': {
@@ -44,7 +47,6 @@ export const meta: { [key: string]: any } = {
},
// Tools
'asset-buyer': {
// @TODO: Fix description
title: 'Asset buyer',
description: '',
topics: ['Mesh'],
@@ -53,9 +55,10 @@ export const meta: { [key: string]: any } = {
isFeatured: true,
tags: ['Relayer'],
type: 'Docker images',
path: 'tools/@0x/asset-buyer/v6.1.11/reference.mdx',
},
'ethereum-types': {
// @TODO: Fix description
title: 'Ethereum types',
description: '',
topics: ['Mesh'],
@@ -64,5 +67,7 @@ export const meta: { [key: string]: any } = {
isFeatured: true,
tags: ['Protocol developer'],
type: 'Command-line tools',
path: 'tools/ethereum-types/v2.1.4/reference.mdx',
},
};

View File

@@ -34,6 +34,7 @@ const config = {
less: path.join(__dirname, '/less'),
sass: path.join(__dirname, '/sass'),
md: path.join(__dirname, '/md'),
mdx: path.join(__dirname, '/mdx'),
},
},
module: {