-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for Elm assets #1968
Merged
Merged
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
563297e
Implemented change so that any asset can force a reload in HMR.
benthepoet 7f2d72e
Added asset for Elm.
benthepoet 0386b89
Registered extension.
benthepoet acca76d
Set Elm assets to force a page reload.
benthepoet fad0f8c
Added comment referencing optimal Terser configuration.
benthepoet 2062007
Added integration test for Elm.
benthepoet ae839b3
Excluded package folder.
benthepoet 52e5aac
Fixed test.
benthepoet 7e44412
Fixed path for integration test.
benthepoet 1c1c937
Fixed linting issues.
benthepoet a2127ea
Added test for production mode.
benthepoet a6ec420
Fixed module path.
benthepoet 6844a1b
Removed assertion.
benthepoet 51d07ad
Fixed assertion for minification test.
benthepoet 0990345
Updated comment.
benthepoet c1a8e8e
Removed formatting in GraphQL test.
benthepoet ba651ce
Updated yarn.lock.
benthepoet ecfd64a
Switched minification to a single pass.
benthepoet dcd7d42
Fixed minification options.
benthepoet c013178
Disabled rename pass.
benthepoet 4026284
Added error handling for minification.
benthepoet 646dc93
Adjusted error throw.
benthepoet 28a5823
Set compress to perform 2 passes.
benthepoet 03bd986
Fixed linting issue.
benthepoet c0766da
Renamed flag to be better describe its purpose.
benthepoet 9cb6d70
Added Elm package file to asset dependencies.
benthepoet 100ffda
Added a missing await.
benthepoet a588ea8
Adjusted package version and replaced helper function.
benthepoet 71358f4
Removed a redundant package.
benthepoet d856fd6
Auto install elm and create elm.json if needed
devongovett File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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,131 @@ | ||
const process = require('process'); | ||
const Asset = require('../Asset'); | ||
const commandExists = require('command-exists'); | ||
const localRequire = require('../utils/localRequire'); | ||
const {minify} = require('terser'); | ||
const path = require('path'); | ||
const spawn = require('cross-spawn'); | ||
|
||
class ElmAsset extends Asset { | ||
constructor(name, options) { | ||
super(name, options); | ||
this.type = 'js'; | ||
this.hmrPageReload = true; | ||
} | ||
|
||
async parse() { | ||
let options = { | ||
cwd: path.dirname(this.name) | ||
}; | ||
|
||
// If elm is not installed globally, install it locally. | ||
try { | ||
await commandExists('elm'); | ||
} catch (err) { | ||
await localRequire('elm', this.name); | ||
options.pathToElm = path.join( | ||
path.dirname(require.resolve('elm')), | ||
'bin', | ||
'elm' | ||
); | ||
} | ||
|
||
this.elm = await localRequire('node-elm-compiler', this.name); | ||
|
||
// Ensure that an elm.json file exists, and initialize one if not. | ||
let elmConfig = await this.getConfig(['elm.json'], {load: false}); | ||
if (!elmConfig) { | ||
await this.createElmConfig(options); | ||
|
||
// Ensure we are watching elm.json for changes | ||
await this.getConfig(['elm.json'], {load: false}); | ||
} | ||
|
||
if (this.options.minify) { | ||
options.optimize = true; | ||
} | ||
|
||
let compiled = await this.elm.compileToString(this.name, options); | ||
this.contents = compiled.toString(); | ||
} | ||
|
||
async collectDependencies() { | ||
let dependencies = await this.elm.findAllDependencies(this.name); | ||
for (let dependency of dependencies) { | ||
this.addDependency(dependency, {includedInParent: true}); | ||
} | ||
} | ||
|
||
async createElmConfig(options) { | ||
let cp = spawn(options.pathToElm || 'elm', ['init']); | ||
cp.stdin.write('y\n'); | ||
|
||
return new Promise((resolve, reject) => { | ||
cp.on('error', reject); | ||
cp.on('close', function(code) { | ||
if (code !== 0) { | ||
return reject(new Error('elm init failed.')); | ||
} | ||
|
||
return resolve(); | ||
}); | ||
}); | ||
} | ||
|
||
async generate() { | ||
let output = this.contents; | ||
|
||
if (this.options.minify) { | ||
output = pack(output); | ||
} | ||
|
||
return { | ||
[this.type]: output | ||
}; | ||
|
||
// Recommended minification | ||
// Based on: | ||
// - http://elm-lang.org/0.19.0/optimize | ||
function pack(source) { | ||
let options = { | ||
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, | ||
rename: false | ||
}; | ||
|
||
let result = minify(source, options); | ||
|
||
if (result.error) { | ||
throw result.error; | ||
} | ||
|
||
return result.code; | ||
} | ||
} | ||
} | ||
|
||
module.exports = ElmAsset; |
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,29 @@ | ||
const assert = require('assert'); | ||
const fs = require('../src/utils/fs'); | ||
const {bundle, assertBundleTree, run} = require('./utils'); | ||
|
||
describe('elm', function() { | ||
it('should produce a basic Elm bundle', async function() { | ||
let b = await bundle(__dirname + '/integration/elm/index.js'); | ||
|
||
await assertBundleTree(b, { | ||
type: 'js', | ||
assets: ['Main.elm', 'index.js'] | ||
}); | ||
|
||
let output = await run(b); | ||
assert.equal(typeof output().Elm.Main.init, 'function'); | ||
}); | ||
|
||
it('should minify Elm in production mode', async function() { | ||
let b = await bundle(__dirname + '/integration/elm/index.js', { | ||
production: true | ||
}); | ||
|
||
let output = await run(b); | ||
assert.equal(typeof output().Elm.Main.init, 'function'); | ||
|
||
let js = await fs.readFile(__dirname + '/dist/index.js', 'utf8'); | ||
assert(!js.includes('elm$core')); | ||
}); | ||
}); |
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,24 @@ | ||
{ | ||
benthepoet marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"type": "application", | ||
"source-directories": [ | ||
"src" | ||
], | ||
"elm-version": "0.19.0", | ||
"dependencies": { | ||
"direct": { | ||
"elm/browser": "1.0.0", | ||
"elm/core": "1.0.0", | ||
"elm/html": "1.0.0" | ||
}, | ||
"indirect": { | ||
"elm/json": "1.0.0", | ||
"elm/time": "1.0.0", | ||
"elm/url": "1.0.0", | ||
"elm/virtual-dom": "1.0.0" | ||
} | ||
}, | ||
"test-dependencies": { | ||
"direct": {}, | ||
"indirect": {} | ||
} | ||
} |
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,5 @@ | ||
var local = require('./src/Main.elm'); | ||
|
||
module.exports = function () { | ||
return local; | ||
}; |
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,47 @@ | ||
module Main exposing (main) | ||
|
||
import Browser | ||
import Html exposing (Html, button, div, text) | ||
import Html.Events exposing (onClick) | ||
|
||
|
||
type alias Model = | ||
{ count : Int } | ||
|
||
|
||
initialModel : Model | ||
initialModel = | ||
{ count = 0 } | ||
|
||
|
||
type Msg | ||
= Increment | ||
| Decrement | ||
|
||
|
||
update : Msg -> Model -> Model | ||
update msg model = | ||
case msg of | ||
Increment -> | ||
{ model | count = model.count + 1 } | ||
|
||
Decrement -> | ||
{ model | count = model.count - 1 } | ||
|
||
|
||
view : Model -> Html Msg | ||
view model = | ||
div [] | ||
[ button [ onClick Increment ] [ text "+1" ] | ||
, div [] [ text <| String.fromInt model.count ] | ||
, button [ onClick Decrement ] [ text "-1" ] | ||
] | ||
|
||
|
||
main : Program () Model Msg | ||
main = | ||
Browser.sandbox | ||
{ init = initialModel | ||
, view = view | ||
, update = update | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this dependency used for? I don't see it used anywhere in the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This provides the actual
elm
binaries thatnode-elm-compiler
uses to compile the source files. The package isn't a dependency ofnode-elm-compiler
, so unfortunately we have to pull it in.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see. So since this is a dev dependency in parcel, so we might need to install it in a user's project as well, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, updated to auto install
elm
when the command isn't available globally.