Merge branch 'master' into i18n
This commit is contained in:
commit
31190ea5b0
22 changed files with 147 additions and 84 deletions
|
@ -1,5 +1,5 @@
|
|||
[bumpversion]
|
||||
current_version = 0.11.5
|
||||
current_version = 0.11.7
|
||||
commit = True
|
||||
tag = True
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)((?P<release>[a-z]+)(?P<candidate>\d+))?
|
||||
|
|
27
CHANGELOG.md
27
CHANGELOG.md
|
@ -27,6 +27,33 @@ Web UI version numbers should always match the corresponding version of LBRY App
|
|||
*
|
||||
*
|
||||
|
||||
## [0.11.7] - 2017-05-30
|
||||
|
||||
### Changed
|
||||
* Video player switched from plyr to render-media
|
||||
|
||||
|
||||
### Fixed
|
||||
* Video player should behave better on streaming
|
||||
* Daemon times out more quickly when it cannot start
|
||||
* Connection should fail more cleanly, rather than get stuck entirely
|
||||
* Closing modal dialogs was broken on some download and stream errors
|
||||
* Discover landing page improperly showed loading error when it was loading correctly
|
||||
|
||||
|
||||
|
||||
## [0.11.6] - 2017-05-29
|
||||
|
||||
### Changed
|
||||
* Do not use a separate claim cache for publishes
|
||||
|
||||
|
||||
### Fixed
|
||||
* Upgrade process should now works on Windows
|
||||
* Crudely handle failed publishes missing outpoints
|
||||
|
||||
|
||||
|
||||
## [0.11.5] - 2017-05-28
|
||||
|
||||
### Fixed
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "LBRY",
|
||||
"version": "0.11.5",
|
||||
"version": "0.11.7",
|
||||
"main": "main.js",
|
||||
"description": "LBRY is a fully decentralized, open-source protocol facilitating the discovery, access, and (sometimes) purchase of data.",
|
||||
"author": {
|
||||
|
|
|
@ -209,7 +209,7 @@ export function doLoadVideo(uri) {
|
|||
}
|
||||
}
|
||||
|
||||
export function doPurchaseUri(uri) {
|
||||
export function doPurchaseUri(uri, purchaseModalName) {
|
||||
return function(dispatch, getState) {
|
||||
const state = getState()
|
||||
const balance = selectBalance(state)
|
||||
|
@ -244,7 +244,7 @@ export function doPurchaseUri(uri) {
|
|||
if (cost > balance) {
|
||||
dispatch(doOpenModal('notEnoughCredits'))
|
||||
} else {
|
||||
dispatch(doOpenModal('affirmPurchase'))
|
||||
dispatch(doOpenModal(purchaseModalName))
|
||||
}
|
||||
|
||||
return Promise.resolve()
|
||||
|
@ -274,16 +274,16 @@ export function doFetchClaimsByChannel(uri) {
|
|||
}
|
||||
}
|
||||
|
||||
export function doClaimListMine() {
|
||||
export function doFetchClaimListMine() {
|
||||
return function(dispatch, getState) {
|
||||
dispatch({
|
||||
type: types.CLAIM_LIST_MINE_STARTED
|
||||
type: types.FETCH_CLAIM_LIST_MINE_STARTED
|
||||
})
|
||||
|
||||
|
||||
lbry.claim_list_mine().then((claims) => {
|
||||
dispatch({
|
||||
type: types.CLAIM_LIST_MINE_COMPLETED,
|
||||
type: types.FETCH_CLAIM_LIST_MINE_COMPLETED,
|
||||
data: {
|
||||
claims
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as types from 'constants/action_types'
|
||||
import lbry from 'lbry'
|
||||
import {
|
||||
doClaimListMine
|
||||
doFetchClaimListMine
|
||||
} from 'actions/content'
|
||||
import {
|
||||
selectClaimsByUri,
|
||||
|
@ -110,7 +110,7 @@ export function doFetchFileInfosAndPublishedClaims() {
|
|||
isFileInfoListPending = selectFileListIsPending(state)
|
||||
|
||||
if (isClaimListMinePending === undefined) {
|
||||
dispatch(doClaimListMine())
|
||||
dispatch(doFetchClaimListMine())
|
||||
}
|
||||
|
||||
if (isFileInfoListPending === undefined) {
|
||||
|
|
|
@ -66,7 +66,7 @@ const perform = (dispatch) => ({
|
|||
dispatch(doDeleteFile(fileInfo, deleteFromComputer))
|
||||
},
|
||||
openModal: (modal) => dispatch(doOpenModal(modal)),
|
||||
startDownload: (uri) => dispatch(doPurchaseUri(uri)),
|
||||
startDownload: (uri) => dispatch(doPurchaseUri(uri, 'affirmPurchase')),
|
||||
loadVideo: (uri) => dispatch(doLoadVideo(uri)),
|
||||
})
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ class FileActions extends React.Component {
|
|||
<DropDownMenuItem key={1} onClick={() => openModal('confirmRemove')} label={__("Remove...")} />
|
||||
</DropDownMenu> : '' }
|
||||
<Modal type="confirm" isOpen={modal == 'affirmPurchase'}
|
||||
contentLabel={__("Confirm Purchase")} onConfirmed={this.onAffirmPurchase.bind(this)} onAborted={this.props.closeModal}>
|
||||
contentLabel="Confirm Purchase" onConfirmed={this.onAffirmPurchase.bind(this)} onAborted={closeModal}>
|
||||
{__("This will purchase")} <strong>{title}</strong> {__("for")} <strong><FilePrice uri={uri} look="plain" /></strong> {__("credits")}.
|
||||
</Modal>
|
||||
<Modal isOpen={modal == 'notEnoughCredits'} contentLabel={__("Not enough credits")}
|
||||
|
|
|
@ -31,9 +31,11 @@ class LoadScreen extends React.Component {
|
|||
<img src={imgSrc} alt="LBRY"/>
|
||||
<div className="load-screen__message">
|
||||
<h3>
|
||||
<BusyMessage message={this.props.message} />
|
||||
{!this.props.isWarning ?
|
||||
<BusyMessage message={this.props.message} /> :
|
||||
<span><Icon icon="icon-warning" />{' ' + this.props.message}</span> }
|
||||
</h3>
|
||||
{this.props.isWarning ? <Icon icon="icon-warning" /> : null} <span className={'load-screen__details ' + (this.props.isWarning ? 'load-screen__details--warning' : '')}>{this.props.details}</span>
|
||||
<span className={'load-screen__details ' + (this.props.isWarning ? 'load-screen__details--warning' : '')}>{this.props.details}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -12,7 +12,8 @@ export class SplashScreen extends React.Component {
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
details: __('Starting daemon'),
|
||||
details: 'Starting daemon',
|
||||
message: "Connecting",
|
||||
isLagging: false,
|
||||
};
|
||||
}
|
||||
|
@ -29,11 +30,12 @@ export class SplashScreen extends React.Component {
|
|||
// TODO: This is a hack, and the logic should live in the daemon
|
||||
// to give us a better sense of when we are actually started
|
||||
this.setState({
|
||||
details: __('Waiting for name resolution'),
|
||||
message: "Testing Network",
|
||||
details: "Waiting for name resolution",
|
||||
isLagging: false
|
||||
});
|
||||
|
||||
lbry.resolve({uri: 'lbry://one'}).then(() => {
|
||||
lbry.resolve({uri: "lbry://one"}).then(() => {
|
||||
this.props.onLoadDone();
|
||||
});
|
||||
return;
|
||||
|
@ -48,21 +50,19 @@ export class SplashScreen extends React.Component {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
lbry.connect().then((isConnected) => {
|
||||
if (isConnected) {
|
||||
this.updateStatus();
|
||||
} else {
|
||||
lbry.connect()
|
||||
.then(() => { this.updateStatus() })
|
||||
.catch(() => {
|
||||
this.setState({
|
||||
isLagging: true,
|
||||
message: __("Failed to connect to LBRY"),
|
||||
details: __("LBRY was unable to start and connect properly.")
|
||||
message: "Connection Failure",
|
||||
details: "Try closing all LBRY processes and starting again. If this still happpens, your anti-virus software or firewall may be preventing LBRY from connecting. Contact hello@lbry.io if you think this is a software bug."
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
return <LoadScreen message={this.props.message} details={this.state.details} isWarning={this.state.isLagging} />
|
||||
return <LoadScreen message={this.state.message} details={this.state.details} isWarning={this.state.isLagging} />
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ const makeSelect = () => {
|
|||
|
||||
const perform = (dispatch) => ({
|
||||
loadVideo: (uri) => dispatch(doLoadVideo(uri)),
|
||||
purchaseUri: (uri) => dispatch(doPurchaseUri(uri)),
|
||||
purchaseUri: (uri) => dispatch(doPurchaseUri(uri, 'affirmPurchaseAndPlay')),
|
||||
closeModal: () => dispatch(doCloseModal()),
|
||||
})
|
||||
|
||||
|
|
|
@ -52,28 +52,25 @@ class VideoPlayButton extends React.Component {
|
|||
className="video__play-button"
|
||||
icon="icon-play"
|
||||
onClick={this.onWatchClick.bind(this)} />
|
||||
{modal}
|
||||
<Modal contentLabel={__("Not enough credits")} isOpen={modal == 'notEnoughCredits'} onConfirmed={() => { this.closeModal() }}>
|
||||
<Modal contentLabel="Not enough credits" isOpen={modal == 'notEnoughCredits'} onConfirmed={closeModal}>
|
||||
{__("You don't have enough LBRY credits to pay for this stream.")}
|
||||
</Modal>
|
||||
<Modal
|
||||
type="confirm"
|
||||
isOpen={modal == 'affirmPurchase'}
|
||||
isOpen={modal == 'affirmPurchaseAndPlay'}
|
||||
contentLabel={__("Confirm Purchase")}
|
||||
onConfirmed={this.onPurchaseConfirmed.bind(this)}
|
||||
onAborted={closeModal}>
|
||||
{__("This will purchase")} <strong>{title}</strong> {__("for")} <strong><FilePrice uri={uri} look="plain" /></strong> {__("credits")}.
|
||||
</Modal>
|
||||
<Modal
|
||||
isOpen={modal == 'timedOut'} onConfirmed={() => { this.closeModal() }} contentLabel="Timed Out">
|
||||
isOpen={modal == 'timedOut'} onConfirmed={closeModal} contentLabel="Timed Out">
|
||||
{__("Sorry, your download timed out :(")}
|
||||
</Modal>
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
|
||||
const plyr = require('plyr')
|
||||
|
||||
class Video extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
@ -114,7 +111,7 @@ class Video extends React.Component {
|
|||
isPlaying || isLoading ?
|
||||
(!isReadyToPlay ?
|
||||
<span>{__("this is the world's worst loading screen and we shipped our software with it anyway...")} <br /><br />{loadStatusMessage}</span> :
|
||||
<VideoPlayer poster={metadata.thumbnail} autoplay={isPlaying} downloadPath={fileInfo.download_path} />) :
|
||||
<VideoPlayer filename={fileInfo.file_name} poster={metadata.thumbnail} downloadPath={fileInfo.download_path} />) :
|
||||
<div className="video__cover" style={{backgroundImage: 'url("' + metadata.thumbnail + '")'}}>
|
||||
<VideoPlayButton startPlaying={this.startPlaying.bind(this)} {...this.props} />
|
||||
</div>
|
||||
|
@ -123,18 +120,28 @@ class Video extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
const from = require('from2')
|
||||
const player = require('render-media')
|
||||
const fs = require('fs')
|
||||
|
||||
class VideoPlayer extends React.Component {
|
||||
componentDidMount() {
|
||||
const elem = this.refs.video
|
||||
const {
|
||||
autoplay,
|
||||
downloadPath,
|
||||
contentType,
|
||||
filename,
|
||||
} = this.props
|
||||
const players = plyr.setup(elem)
|
||||
if (autoplay) {
|
||||
players[0].play()
|
||||
const file = {
|
||||
name: filename,
|
||||
createReadStream: (opts) => {
|
||||
return fs.createReadStream(downloadPath, opts)
|
||||
}
|
||||
}
|
||||
player.render(file, elem, {
|
||||
autoplay: true,
|
||||
controls: true,
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -145,7 +152,7 @@ class VideoPlayer extends React.Component {
|
|||
} = this.props
|
||||
|
||||
return (
|
||||
<video controls id="video" ref="video" style={{backgroundImage: "url('" + poster + "')"}} >
|
||||
<video controls ref="video" style={{backgroundImage: "url('" + poster + "')"}} >
|
||||
<source src={downloadPath} type={contentType} />
|
||||
</video>
|
||||
)
|
||||
|
|
|
@ -40,8 +40,8 @@ export const RESOLVE_URI_COMPLETED = 'RESOLVE_URI_COMPLETED'
|
|||
export const RESOLVE_URI_CANCELED = 'RESOLVE_URI_CANCELED'
|
||||
export const FETCH_CHANNEL_CLAIMS_STARTED = 'FETCH_CHANNEL_CLAIMS_STARTED'
|
||||
export const FETCH_CHANNEL_CLAIMS_COMPLETED = 'FETCH_CHANNEL_CLAIMS_COMPLETED'
|
||||
export const CLAIM_LIST_MINE_STARTED = 'CLAIM_LIST_MINE_STARTED'
|
||||
export const CLAIM_LIST_MINE_COMPLETED = 'CLAIM_LIST_MINE_COMPLETED'
|
||||
export const FETCH_CLAIM_LIST_MINE_STARTED = 'FETCH_CLAIM_LIST_MINE_STARTED'
|
||||
export const FETCH_CLAIM_LIST_MINE_COMPLETED = 'FETCH_CLAIM_LIST_MINE_COMPLETED'
|
||||
export const FILE_LIST_STARTED = 'FILE_LIST_STARTED'
|
||||
export const FILE_LIST_COMPLETED = 'FILE_LIST_COMPLETED'
|
||||
export const FETCH_FILE_INFO_STARTED = 'FETCH_FILE_INFO_STARTED'
|
||||
|
|
|
@ -96,26 +96,27 @@ lbry.call = function (method, params, callback, errorCallback, connectFailedCall
|
|||
lbry._connectPromise = null;
|
||||
lbry.connect = function() {
|
||||
if (lbry._connectPromise === null) {
|
||||
|
||||
lbry._connectPromise = new Promise((resolve, reject) => {
|
||||
|
||||
let tryNum = 0
|
||||
|
||||
function checkDaemonStartedFailed() {
|
||||
console.log('status error try num ' + tryNum)
|
||||
if (tryNum <= 100) { // Move # of tries into constant or config option
|
||||
setTimeout(() => {
|
||||
tryNum++
|
||||
checkDaemonStarted();
|
||||
}, tryNum < 50 ? 400 : 1000);
|
||||
}
|
||||
else {
|
||||
reject(new Error("Unable to connect to LBRY"));
|
||||
}
|
||||
}
|
||||
|
||||
// Check every half second to see if the daemon is accepting connections
|
||||
function checkDaemonStarted(tryNum = 0) {
|
||||
lbry.isDaemonAcceptingConnections(function (runningStatus) {
|
||||
if (runningStatus) {
|
||||
resolve(true);
|
||||
}
|
||||
else {
|
||||
if (tryNum <= 600) { // Move # of tries into constant or config option
|
||||
setTimeout(function () {
|
||||
checkDaemonStarted(tryNum + 1);
|
||||
}, tryNum < 100 ? 200 : 1000);
|
||||
}
|
||||
else {
|
||||
reject(new Error(__("Unable to connect to LBRY")));
|
||||
}
|
||||
}
|
||||
});
|
||||
function checkDaemonStarted() {
|
||||
console.log('check daemon started try ' + tryNum)
|
||||
lbry.call('status', {}, resolve, checkDaemonStartedFailed, checkDaemonStartedFailed)
|
||||
}
|
||||
|
||||
checkDaemonStarted();
|
||||
|
@ -125,11 +126,6 @@ lbry.connect = function() {
|
|||
return lbry._connectPromise;
|
||||
}
|
||||
|
||||
lbry.isDaemonAcceptingConnections = function (callback) {
|
||||
// Returns true/false whether the daemon is at a point it will start returning status
|
||||
lbry.call('status', {}, () => callback(true), null, () => callback(false))
|
||||
};
|
||||
|
||||
lbry.checkAddressIsMine = function(address, callback) {
|
||||
lbry.call('address_is_mine', {address: address}, callback);
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ var init = function() {
|
|||
if (window.sessionStorage.getItem('loaded') == 'y') {
|
||||
onDaemonReady();
|
||||
} else {
|
||||
ReactDOM.render(<SplashScreen message={__("Connecting")} onLoadDone={onDaemonReady} />, canvas);
|
||||
ReactDOM.render(<SplashScreen onLoadDone={onDaemonReady} />, canvas);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -33,6 +33,10 @@ class DiscoverPage extends React.Component{
|
|||
featuredUris,
|
||||
fetchingFeaturedUris,
|
||||
} = this.props
|
||||
const failedToLoad = !fetchingFeaturedUris && (
|
||||
featuredUris === undefined ||
|
||||
(featuredUris !== undefined && Object.keys(featuredUris).length === 0)
|
||||
)
|
||||
|
||||
return (
|
||||
<main>
|
||||
|
@ -47,7 +51,7 @@ class DiscoverPage extends React.Component{
|
|||
))
|
||||
}
|
||||
{
|
||||
typeof featuredUris !== undefined &&
|
||||
failedToLoad &&
|
||||
<div className="empty">{__("Failed to load landing content.")}</div>
|
||||
}
|
||||
</main>
|
||||
|
|
|
@ -40,20 +40,33 @@ reducers[types.RESOLVE_URI_CANCELED] = function(state, action) {
|
|||
}
|
||||
|
||||
|
||||
reducers[types.CLAIM_LIST_MINE_STARTED] = function(state, action) {
|
||||
reducers[types.FETCH_CLAIM_LIST_MINE_STARTED] = function(state, action) {
|
||||
return Object.assign({}, state, {
|
||||
isClaimListMinePending: true
|
||||
})
|
||||
}
|
||||
|
||||
reducers[types.CLAIM_LIST_MINE_COMPLETED] = function(state, action) {
|
||||
const myClaims = Object.assign({}, state.myClaims)
|
||||
action.data.claims.forEach((claim) => {
|
||||
myClaims[claim.claim_id] = claim
|
||||
reducers[types.FETCH_CLAIM_LIST_MINE_COMPLETED] = function(state, action) {
|
||||
const {
|
||||
claims,
|
||||
} = action.data
|
||||
const myClaims = new Set(state.myClaims)
|
||||
const byUri = Object.assign({}, state.claimsByUri)
|
||||
|
||||
claims.forEach(claim => {
|
||||
const uri = lbryuri.build({
|
||||
contentName: claim.name,
|
||||
claimId: claim.claim_id,
|
||||
claimSequence: claim.nout,
|
||||
})
|
||||
myClaims.add(uri)
|
||||
byUri[uri] = claim
|
||||
})
|
||||
|
||||
return Object.assign({}, state, {
|
||||
isClaimListMinePending: false,
|
||||
myClaims: myClaims
|
||||
myClaims: myClaims,
|
||||
claimsByUri: byUri,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,9 @@ reducers[types.FILE_LIST_COMPLETED] = function(state, action) {
|
|||
|
||||
const newFileInfos = Object.assign({}, state.fileInfos)
|
||||
fileInfos.forEach((fileInfo) => {
|
||||
newFileInfos[fileInfo.outpoint] = fileInfo
|
||||
const { outpoint } = fileInfo
|
||||
|
||||
if (outpoint) newFileInfos[fileInfo.outpoint] = fileInfo
|
||||
})
|
||||
|
||||
return Object.assign({}, state, {
|
||||
|
|
|
@ -113,7 +113,7 @@ export const selectUpgradeFilename = createSelector(
|
|||
return `LBRY-${version}.dmg`;
|
||||
case 'linux':
|
||||
return `LBRY_${version}_amd64.deb`;
|
||||
case 'windows':
|
||||
case 'win32':
|
||||
return `LBRY.Setup.${version}.exe`;
|
||||
default:
|
||||
throw 'Unknown platform';
|
||||
|
|
|
@ -42,7 +42,8 @@ const selectMetadataForUri = (state, props) => {
|
|||
const claim = selectClaimForUri(state, props)
|
||||
const metadata = claim && claim.value && claim.value.stream && claim.value.stream.metadata
|
||||
|
||||
return metadata ? metadata : (claim === undefined ? undefined : null)
|
||||
const value = metadata ? metadata : (claim === undefined ? undefined : null)
|
||||
return value
|
||||
}
|
||||
|
||||
export const makeSelectMetadataForUri = () => {
|
||||
|
@ -80,18 +81,20 @@ export const selectClaimListMineIsPending = createSelector(
|
|||
|
||||
export const selectMyClaims = createSelector(
|
||||
_selectState,
|
||||
(state) => state.myClaims || {}
|
||||
(state) => state.myClaims || new Set()
|
||||
)
|
||||
|
||||
export const selectMyClaimsOutpoints = createSelector(
|
||||
selectMyClaims,
|
||||
(claims) => {
|
||||
if (!claims) {
|
||||
return []
|
||||
}
|
||||
selectClaimsByUri,
|
||||
(claimIds, byUri) => {
|
||||
const outpoints = []
|
||||
|
||||
return Object.values(claims).map((claim) => {
|
||||
return `${claim.txid}:${claim.nout}`
|
||||
claimIds.forEach(claimId => {
|
||||
const claim = byUri[claimId]
|
||||
if (claim) outpoints.push(`${claim.txid}:${claim.nout}`)
|
||||
})
|
||||
|
||||
return outpoints
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "lbry-web-ui",
|
||||
"version": "0.11.5",
|
||||
"version": "0.11.7",
|
||||
"description": "LBRY UI",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
|
@ -22,9 +22,9 @@
|
|||
"babel-cli": "^6.11.4",
|
||||
"babel-preset-es2015": "^6.13.2",
|
||||
"babel-preset-react": "^6.11.1",
|
||||
"from2": "^2.3.0",
|
||||
"jshashes": "^1.0.6",
|
||||
"node-sass": "^3.8.0",
|
||||
"plyr": "^2.0.12",
|
||||
"rc-progress": "^2.0.6",
|
||||
"react": "^15.4.0",
|
||||
"react-dom": "^15.4.0",
|
||||
|
@ -33,6 +33,7 @@
|
|||
"redux": "^3.6.0",
|
||||
"redux-logger": "^3.0.1",
|
||||
"redux-thunk": "^2.2.0",
|
||||
"render-media": "^2.10.0",
|
||||
"reselect": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -42,7 +42,11 @@ module.exports = {
|
|||
cacheDirectory: true,
|
||||
presets:[ 'es2015', 'react', 'stage-2' ]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /mime\.json$/,
|
||||
loader: 'json',
|
||||
},
|
||||
]
|
||||
},
|
||||
target: 'electron-main',
|
||||
|
|
|
@ -48,7 +48,11 @@ module.exports = {
|
|||
cacheDirectory: true,
|
||||
presets:[ 'es2015', 'react', 'stage-2' ]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /mime\.json$/,
|
||||
loader: 'json',
|
||||
},
|
||||
]
|
||||
},
|
||||
target: 'electron-main',
|
||||
|
|
Loading…
Reference in a new issue