-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
9e0bb77
commit cebbec7
Showing
11 changed files
with
271 additions
and
29 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
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
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 |
---|---|---|
@@ -1,59 +1,82 @@ | ||
import assert from 'assert'; | ||
import {bundle, assertBundleTree, run, outputFS} from '@parcel/test-utils'; | ||
import path from 'path'; | ||
import { | ||
bundle, | ||
distDir, | ||
assertBundles, | ||
run, | ||
outputFS, | ||
} from '@parcel/test-utils'; | ||
|
||
describe.skip('elm', function() { | ||
describe('elm', function() { | ||
it('should produce a basic Elm bundle', async function() { | ||
let b = await bundle(__dirname + '/integration/elm/index.js'); | ||
let b = await bundle(path.join(__dirname, '/integration/elm/index.js')); | ||
|
||
await assertBundleTree(b, { | ||
type: 'js', | ||
assets: ['Main.elm', 'index.js'], | ||
}); | ||
await assertBundles(b, [ | ||
{ | ||
type: 'js', | ||
assets: ['Main.elm', 'index.js'], | ||
}, | ||
]); | ||
|
||
let output = await run(b); | ||
assert.equal(typeof output().Elm.Main.init, 'function'); | ||
}); | ||
it('should produce a elm bundle with debugger', async function() { | ||
let b = await bundle(__dirname + '/integration/elm/index.js'); | ||
let b = await bundle(path.join(__dirname, '/integration/elm/index.js')); | ||
|
||
await run(b); | ||
let js = await outputFS.readFile(__dirname + '/dist/index.js', 'utf8'); | ||
let js = await outputFS.readFile(path.join(distDir, 'index.js'), 'utf8'); | ||
assert(js.includes('elm$browser$Debugger')); | ||
}); | ||
|
||
it('should apply elm-hot if HMR is enabled', async function() { | ||
let b = await bundle(__dirname + '/integration/elm/index.js', { | ||
hmr: true, | ||
let b = await bundle(path.join(__dirname, '/integration/elm/index.js'), { | ||
hot: true, | ||
}); | ||
|
||
await assertBundleTree(b, { | ||
type: 'js', | ||
assets: ['Main.elm', 'hmr-runtime.js', 'index.js'], | ||
}); | ||
await assertBundles(b, [ | ||
{ | ||
type: 'js', | ||
assets: ['HMRRuntime.js', 'Main.elm', 'index.js'], | ||
}, | ||
]); | ||
|
||
let js = await outputFS.readFile(__dirname + '/dist/index.js', 'utf8'); | ||
let js = await outputFS.readFile(path.join(distDir, 'index.js'), 'utf8'); | ||
assert(js.includes('[elm-hot]')); | ||
}); | ||
|
||
it('should remove debugger in production', async function() { | ||
let b = await bundle(__dirname + '/integration/elm/index.js', { | ||
production: true, | ||
let b = await bundle(path.join(__dirname, '/integration/elm/index.js'), { | ||
mode: 'production', | ||
}); | ||
|
||
await run(b); | ||
let js = await outputFS.readFile(__dirname + '/dist/index.js', 'utf8'); | ||
let js = await outputFS.readFile(path.join(distDir, 'index.js'), 'utf8'); | ||
assert(!js.includes('elm$browser$Debugger')); | ||
}); | ||
|
||
it('should remove debugger when environment variable `PARCEL_ELM_NO_DEBUG` is set to true', async function() { | ||
let b = await bundle(path.join(__dirname, '/integration/elm/index.js'), { | ||
env: {PARCEL_ELM_NO_DEBUG: true}, | ||
}); | ||
|
||
await run(b); | ||
let js = await outputFS.readFile(path.join(distDir, 'index.js'), 'utf8'); | ||
assert(!js.includes('elm$browser$Debugger')); | ||
}); | ||
|
||
it('should minify Elm in production mode', async function() { | ||
let b = await bundle(__dirname + '/integration/elm/index.js', { | ||
production: true, | ||
let b = await bundle(path.join(__dirname, '/integration/elm/index.js'), { | ||
mode: 'production', | ||
minify: true, | ||
}); | ||
|
||
let output = await run(b); | ||
assert.equal(typeof output().Elm.Main.init, 'function'); | ||
await run(b); | ||
|
||
let js = await outputFS.readFile(__dirname + '/dist/index.js', 'utf8'); | ||
let js = await outputFS.readFile(path.join(distDir, 'index.js'), 'utf8'); | ||
assert(!js.includes('elm$core')); | ||
assert(js.includes('Elm')); | ||
assert(js.includes('init')); | ||
}); | ||
}); |
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
1 change: 1 addition & 0 deletions
1
packages/core/integration-tests/test/integration/elm/package.json
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 @@ | ||
{} |
Empty file.
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
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
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,30 @@ | ||
{ | ||
"name": "@parcel/transformer-elm", | ||
"version": "2.0.0-beta.1", | ||
"license": "MIT", | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"funding": { | ||
"type": "opencollective", | ||
"url": "https://opencollective.com/parcel" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/parcel-bundler/parcel.git" | ||
}, | ||
"main": "lib/ElmTransformer.js", | ||
"source": "src/ElmTransformer.js", | ||
"engines": { | ||
"node": ">= 10.0.0", | ||
"parcel": "^2.0.0-alpha.3.1" | ||
}, | ||
"dependencies": { | ||
"@parcel/diagnostic": "^2.0.0-beta.1", | ||
"@parcel/plugin": "^2.0.0-beta.1", | ||
"command-exists": "^1.2.8", | ||
"cross-spawn": "^7.0.3", | ||
"nullthrows": "^1.1.1", | ||
"terser": "^5.2.1" | ||
} | ||
} |
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,162 @@ | ||
// @flow strict-local | ||
|
||
import {Transformer} from '@parcel/plugin'; | ||
import commandExists from 'command-exists'; | ||
import spawn from 'cross-spawn'; | ||
import path from 'path'; | ||
import {minify} from 'terser'; | ||
import nullthrows from 'nullthrows'; | ||
import ThrowableDiagnostic from '@parcel/diagnostic'; | ||
|
||
let isWorker; | ||
try { | ||
let worker_threads = require('worker_threads'); | ||
isWorker = worker_threads.threadId > 0; | ||
} catch (_) { | ||
isWorker = false; | ||
} | ||
|
||
export default (new Transformer({ | ||
async loadConfig({config, options}) { | ||
const elmConfig = await config.getConfig(['elm.json']); | ||
if (!elmConfig) { | ||
await elmBinaryPath(config.searchPath, options); // Check if elm is even installed | ||
throw new ThrowableDiagnostic({ | ||
diagnostic: { | ||
message: "The 'elm.json' file is missing.", | ||
hints: [ | ||
"Initialize your elm project by running 'elm init'", | ||
"If you installed elm as project dependency then run 'yarn elm init' or 'npx elm init'", | ||
], | ||
}, | ||
}); | ||
} | ||
config.setResult(elmConfig.contents); | ||
}, | ||
|
||
async transform({asset, options}) { | ||
const elmBinary = await elmBinaryPath(asset.filePath, options); | ||
const elm = await options.packageManager.require( | ||
'node-elm-compiler', | ||
asset.filePath, | ||
{ | ||
autoinstall: options.autoinstall, | ||
saveDev: true, | ||
}, | ||
); | ||
|
||
const compilerConfig = { | ||
spawn, | ||
cwd: path.dirname(asset.filePath), | ||
// $FlowFixMe[sketchy-null-string] | ||
debug: !options.env.PARCEL_ELM_NO_DEBUG && options.mode !== 'production', | ||
optimize: asset.env.minify, | ||
}; | ||
asset.invalidateOnEnvChange('PARCEL_ELM_NO_DEBUG'); | ||
for (const filePath of await elm.findAllDependencies(asset.filePath)) { | ||
asset.addIncludedFile(filePath); | ||
} | ||
|
||
// Workaround for `chdir` not working in workers | ||
// this can be removed after https://github.com/isaacs/node-graceful-fs/pull/200 was mergend and used in parcel | ||
process.chdir.disabled = isWorker; | ||
|
||
let code = await compileToString(elm, elmBinary, asset, compilerConfig); | ||
if (options.hot) { | ||
code = await injectHotModuleReloadRuntime(code, asset.filePath, options); | ||
} | ||
if (compilerConfig.optimize) code = await minifyElmOutput(code); | ||
|
||
asset.type = 'js'; | ||
asset.setCode(code); | ||
return [asset]; | ||
}, | ||
}): Transformer); | ||
|
||
async function elmBinaryPath(searchPath, options) { | ||
let elmBinary = await resolveLocalElmBinary(searchPath, options); | ||
|
||
if (elmBinary == null && !commandExists.sync('elm')) { | ||
throw new ThrowableDiagnostic({ | ||
diagnostic: { | ||
message: "Can't find 'elm' binary.", | ||
hints: [ | ||
"You can add it as an dependency for your project by running 'yarn add -D elm' or 'npm add -D elm'", | ||
'If you want to install it globally then follow instructions on https://elm-lang.org/', | ||
], | ||
origin: '@parcel/elm-transformer', | ||
}, | ||
}); | ||
} | ||
|
||
return elmBinary; | ||
} | ||
|
||
async function resolveLocalElmBinary(searchPath, options) { | ||
try { | ||
let result = await options.packageManager.resolve( | ||
'elm/package.json', | ||
searchPath, | ||
{autoinstall: false}, | ||
); | ||
|
||
let bin = nullthrows(result.pkg?.bin); | ||
return path.join( | ||
path.dirname(result.resolved), | ||
typeof bin === 'string' ? bin : bin.elm, | ||
); | ||
} catch (_) { | ||
return null; | ||
} | ||
} | ||
|
||
function compileToString(elm, elmBinary, asset, config) { | ||
return elm.compileToString(asset.filePath, { | ||
pathToElm: elmBinary, | ||
...config, | ||
}); | ||
} | ||
|
||
async function injectHotModuleReloadRuntime(code, filePath, options) { | ||
const elmHMR = await options.packageManager.require('elm-hot', filePath, { | ||
autoinstall: options.autoinstall, | ||
saveDev: true, | ||
}); | ||
return elmHMR.inject(code); | ||
} | ||
|
||
async function minifyElmOutput(source) { | ||
// Recommended minification | ||
// Based on: http://elm-lang.org/0.19.0/optimize | ||
let result = await minify(source, { | ||
compress: { | ||
keep_fargs: false, | ||
passes: 2, | ||
pure_funcs: [ | ||
'F2', | ||
'F3', | ||
'F4', | ||
'F5', | ||
'F6', | ||
'F7', | ||
'F8', | ||
'F9', | ||
'A2', | ||
'A3', | ||
'A4', | ||
'A5', | ||
'A6', | ||
'A7', | ||
'A8', | ||
'A9', | ||
], | ||
pure_getters: true, | ||
unsafe: true, | ||
unsafe_comps: true, | ||
}, | ||
mangle: true, | ||
}); | ||
|
||
if (result.code != null) return result.code; | ||
throw result.error; | ||
} |
Oops, something went wrong.