forked from saltyshiomix/nextron
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
13ce24e
commit 31d4627
Showing
32 changed files
with
8,510 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -57,3 +57,6 @@ typings/ | |
# dotenv environment variables file | ||
.env | ||
|
||
# nextron | ||
.DS_Store | ||
dist |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.gitignore | ||
src | ||
tsconfig.json | ||
webpack.config.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
{ | ||
"name": "nextron", | ||
"version": "0.1.0", | ||
"description": "Fully next.js electron app.", | ||
"repository": "git@github.com:saltyshiomix/nextron.git", | ||
"author": "Yoshihide Shiono <shiono.yoshihide@gmail.com>", | ||
"license": "MIT", | ||
"main": "dist/main.js", | ||
"bin": { | ||
"nextron": "dist/bin/nextron.js" | ||
}, | ||
"scripts": { | ||
"build": "webpack" | ||
}, | ||
"dependencies": { | ||
"app-root-path": "^2.0.1", | ||
"archiver": "^2.1.1", | ||
"asar": "^0.14.3", | ||
"capitalize": "^1.0.0", | ||
"chalk": "^2.4.1", | ||
"chokidar": "^2.0.3", | ||
"commander": "^2.15.1", | ||
"dashify": "^1.0.0", | ||
"dot-prop": "^4.2.0", | ||
"electron": "^1.8.6", | ||
"electron-installer-dmg": "^0.2.1", | ||
"electron-is-dev": "^0.3.0", | ||
"electron-windows-installer": "^1.7.8", | ||
"fs-extra": "^6.0.0", | ||
"globby": "^8.0.1", | ||
"inquirer": "^5.2.0", | ||
"klaw": "^2.1.1", | ||
"next": "^6.0.0", | ||
"ora": "^2.1.0", | ||
"plist": "^3.0.1", | ||
"react": "^16.3.2", | ||
"react-dom": "^16.3.2", | ||
"respawn": "^2.5.0" | ||
}, | ||
"devDependencies": { | ||
"@types/archiver": "^2.1.1", | ||
"@types/capitalize": "^1.0.1", | ||
"@types/chalk": "^2.2.0", | ||
"@types/chokidar": "^1.7.5", | ||
"@types/commander": "^2.12.2", | ||
"@types/dashify": "^1.0.0", | ||
"@types/dot-prop": "^4.2.0", | ||
"@types/fs-extra": "^5.0.2", | ||
"@types/globby": "^6.1.0", | ||
"@types/inquirer": "^0.0.41", | ||
"@types/klaw": "^2.1.1", | ||
"@types/next": "^2.4.9", | ||
"@types/node": "^8.10.11", | ||
"@types/ora": "^1.3.4", | ||
"@types/react": "^16.3.13", | ||
"@types/react-dom": "^16.0.5", | ||
"ts-loader": "^4.2.0", | ||
"typescript": "^2.8.3", | ||
"webpack": "^4.6.0", | ||
"webpack-cli": "^2.0.15", | ||
"webpack-merge": "^4.1.2", | ||
"webpack-node-externals": "^1.7.2", | ||
"webpack-shell-plugin": "^0.5.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { pathExists, remove } from 'fs-extra' | ||
import * as spinner from '../../spinner' | ||
|
||
export default async function clean(directory: string): Promise<void> { | ||
if (!await pathExists(directory)) { | ||
return | ||
} | ||
|
||
spinner.create('Cleaning up previous build') | ||
|
||
try { | ||
await remove(directory) | ||
} catch (err) { | ||
spinner.fail('Not able to clean up output directory') | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import * as fs from 'fs-extra' | ||
import { join, basename } from 'path' | ||
import * as archiver from 'archiver' | ||
import * as spinner from '../../spinner' | ||
|
||
const compress = (outputDir: string, target: string, config: any) => new Promise<void>(async resolve => { | ||
if (process.platform !== 'darwin') { | ||
resolve() | ||
return | ||
} | ||
|
||
spinner.create('Wrapping bundle into a ZIP archive') | ||
|
||
const { slug, version } = config | ||
|
||
const name = `${slug}-${version}-mac.zip` | ||
const path = join(outputDir, name) | ||
const output = fs.createWriteStream(path) | ||
|
||
const archive = archiver('zip', { | ||
zlib: { | ||
level: 9 | ||
} | ||
}) | ||
|
||
output.on('close', resolve) | ||
|
||
archive.pipe(output) | ||
archive.directory(target, basename(target)) | ||
archive.finalize() | ||
}) | ||
|
||
export default compress |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
import { join, relative, sep } from 'path' | ||
import { exec as defaultExec } from 'child_process' | ||
import { promisify } from 'util' | ||
import * as fs from 'fs-extra' | ||
import * as asar from 'asar' | ||
import * as globby from 'globby' | ||
import os from './os' | ||
import * as spinner from '../../spinner' | ||
|
||
const pack = (dest, files) => new Promise(async resolve => { | ||
const stats = {} | ||
|
||
for (const file of files) { | ||
const stat = await fs.stat(file) | ||
|
||
stats[file] = { | ||
type: stat.isDirectory() ? 'directory': 'file', | ||
stat | ||
} | ||
} | ||
|
||
asar.createPackageFromFiles(process.cwd(), dest, files, stats, {}, resolve) | ||
}) | ||
|
||
const clear = async (directory, files) => { | ||
const removers = [] | ||
|
||
for (const file of files) { | ||
const location = join(directory, file) | ||
removers.push(fs.remove(location)) | ||
} | ||
|
||
return Promise.all(removers) | ||
} | ||
|
||
const getDependencies = async (cwd: string): Promise<Set<string>> => { | ||
// We need to ensure to make the process always | ||
// succeed, since npm is putting a lot of useless | ||
// errors into stderr. | ||
const command = 'npm ls --prod --parseable --silent || exit 0' | ||
const exec = promisify(defaultExec) | ||
|
||
let stdout | ||
|
||
try { | ||
({ stdout } = await exec(command, { cwd })) | ||
} catch (err) { | ||
spinner.fail('Not able to run `npm ls` properly') | ||
return | ||
} | ||
|
||
const list = stdout.split('\n').map(dependency => { | ||
const path = relative(cwd, dependency) | ||
const parts = path.split(sep) | ||
const { length } = parts | ||
|
||
if (length <= 2) { | ||
return path | ||
} | ||
|
||
if (path.includes('@') && length <= 3) { | ||
return parts.slice(0, 2).join(sep) | ||
} | ||
|
||
return false | ||
}) | ||
|
||
return new Set(list.filter(Boolean)) | ||
} | ||
|
||
export default async function createBundle(workingDir, outputDir, config) { | ||
spinner.create(`Bundling application for ${os}`) | ||
|
||
const include: string[] = [ | ||
'main', | ||
`renderer${sep}out`, | ||
'package.json', | ||
...await getDependencies(workingDir) | ||
] | ||
|
||
const remove = [ | ||
'default_app.asar' | ||
] | ||
|
||
const isWin = process.platform === 'win32' | ||
const main = join(outputDir, isWin ? 'electron' : `${config.name}.app`) | ||
const parent = join(main, isWin ? 'resources' : 'Contents/Resources') | ||
const target = join(parent, config.asar ? 'app.asar' : 'app') | ||
|
||
if (config.asar) { | ||
// The items within this collection won't be walked. Not their | ||
// contents will be included – only their actual representation | ||
// in the file system. | ||
const files = [ | ||
'renderer', | ||
'node_modules', | ||
...await globby(include, { nodir: false }) | ||
] | ||
|
||
// Create the `.asar` bundle with all necessary files | ||
await pack(target, files) | ||
} else { | ||
const copiers = [] | ||
|
||
for (const path of include) { | ||
const from = join(workingDir, path) | ||
const to = join(target, path) | ||
|
||
copiers.push(fs.copy(from, to)) | ||
} | ||
|
||
// Copy all files into place, without an `.asar` archive | ||
await Promise.all(copiers) | ||
} | ||
|
||
if (!isWin) { | ||
const icon = { | ||
origin: config.macOS.icon, | ||
target: join(parent, `${config.slug}.icns`) | ||
} | ||
|
||
await fs.copy(icon.origin, icon.target) | ||
} | ||
|
||
// Remove any useless files from the bundle | ||
await clear(parent, remove) | ||
|
||
return main | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import { join, resolve } from 'path' | ||
import * as generateDMG from 'electron-installer-dmg' | ||
import * as generateEXE from 'electron-windows-installer' | ||
import * as spinner from '../../spinner' | ||
|
||
const createDMG = (outputDir, appPath, config) => new Promise(resolve => { | ||
const { name, slug, version } = config | ||
const background = join(__dirname, '../../assets/background.png') | ||
const dmgPath = join(outputDir, `${slug}-${version}.dmg`) | ||
|
||
const contents = [ | ||
{ | ||
x: 420, | ||
y: 150, | ||
type: 'link', | ||
path: '/Applications' | ||
}, | ||
{ | ||
x: 125, | ||
y: 150, | ||
type: 'file', | ||
path: appPath | ||
} | ||
] | ||
|
||
generateDMG({ | ||
name, | ||
appPath, | ||
dmgPath, | ||
background, | ||
overwrite: true, | ||
contents | ||
}, err => { | ||
if (err) { | ||
spinner.fail('Not able to generate installer') | ||
} | ||
|
||
resolve() | ||
}) | ||
}) | ||
|
||
const createEXE = (outputDirectory, appDirectory, config, cwd) => { | ||
const { name: title, slug, version, windows } = config | ||
|
||
const setup: any = { | ||
appDirectory, | ||
outputDirectory, | ||
setupIcon: windows.setupIcon, | ||
iconUrl: windows.icon, | ||
authors: 'ACME, Inc.', | ||
version, | ||
setupExe: `${slug}-${version}-setup.exe`, | ||
title, | ||
exe: 'electron.exe' | ||
} | ||
|
||
if (!windows.msi) { | ||
setup.noMsi = true | ||
} | ||
|
||
if (windows.loadingGIF) { | ||
setup.loadingGif = resolve(cwd, windows.loadingGIF) | ||
} | ||
|
||
return generateEXE(setup) | ||
} | ||
|
||
export default async function createInstaller(outputDir, appPath, config, cwd) { | ||
spinner.create('Generating installation wizard') | ||
|
||
if (process.platform === 'darwin') { | ||
return createDMG(outputDir, appPath, config) | ||
} | ||
|
||
return createEXE(outputDir, appPath, config, cwd) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { join } from 'path' | ||
import { promisify } from 'util' | ||
import { exec as defaultExec } from 'child_process' | ||
import * as spinner from '../../spinner' | ||
|
||
export default async function exportRenderer(): Promise<void> { | ||
spinner.create('Building renderer code') | ||
|
||
const cwd = process.cwd() | ||
const renderer = join(cwd, 'renderer') | ||
const exec = promisify(defaultExec) | ||
|
||
let stderr | ||
|
||
try { | ||
({ stderr } = await exec(`npx next build ${renderer}`, { cwd })) | ||
} catch (err) { | ||
spinner.fail('Not able to build renderer code') | ||
return | ||
} | ||
|
||
if (stderr && !stderr.includes('must be of type')) { | ||
console.error(stderr) | ||
process.exit(1) | ||
} | ||
|
||
spinner.create('Generating static bundle from renderer code') | ||
|
||
try { | ||
({ stderr } = await exec(`next export ${renderer}`, { cwd })) | ||
// ({ stderr } = await exec(`npx next export ${renderer}`, { cwd })) | ||
} catch (err) { | ||
spinner.fail('Not able to export renderer code') | ||
return | ||
} | ||
|
||
if (stderr && !stderr.includes('must be of type')) { | ||
console.error(stderr) | ||
process.exit(1) | ||
} | ||
} |
Oops, something went wrong.