Skip to content
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

Support for custom webpack config in reload workflow #119

Merged
merged 6 commits into from
Apr 26, 2017
Merged

Support for custom webpack config in reload workflow #119

merged 6 commits into from
Apr 26, 2017

Conversation

jeroentervoorde
Copy link

I implemented this when i ran into an issue using leaflet assets which contain images and require loader configuration (according to my very minimal webpack knowledge..). This failed when using reload workflow. The bundled js is now created using the optional webpack configuration set by "webpackConfigFile in webpackReload"

To be able to scope the setting i added the fastOptJS::webpackReload task which does the same thing as fastOptJS::webpack with reloadWorkflow enabled.

The reloadWorkflow setting still works and also supports the webpackConfigFile setting.

If the approach is ok i'll try to add a test.

- Added a task fastOptJS::webpackReload equivalent to fastOptJS::webpack with reloadWorflow := true.
- Support webpack config using webpackConfigFile setting scoped to webpackReload task
@scala-jenkins
Copy link
Collaborator

Can one of the admins verify this patch?

Webpack.run(entryPoint.absolutePath, bundleFile.absolutePath)(workingDir, logger)
customWebpackConfigFile match {
case Some(configFile) =>
Webpack.run("--config", configFile.getAbsolutePath, entryPoint.absolutePath, bundleFile.absolutePath)(workingDir, logger)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does that mean that webpack still uses the given entryPoint and bundleFile instead of using those given in the configuration file?

Copy link
Author

@jeroentervoorde jeroentervoorde Apr 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it doesn't. I created a stripped down version of my webpack config containing only loader and rules configuration:

module.exports = {
  module: {
    loaders: [
     {
        test: /\.(jpe?g|png|gif|svg)$/i,
        loaders: [
          'file?hash=sha512&digest=hex&name=[hash].[ext]',
          'image-webpack?bypassOnDebug&optimizationLevel=7&interlaced=false'
        ]
      }
    ],
    rules: [
      {
        test: /\.css$/,
        use: [ 'style-loader', 'css-loader' ]
      },
      {
        test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
        loader: 'url-loader',
        options: {
          limit: 10000
        }
      }
    ]
  }
}

I tried if the command option for entry point would override the value in the config file but unfortunately it does not.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That’s great to be able to use a custom configuration file as you do, but I think that’s not good if we have to duplicate parts of the config between the “reload workflow” and the usual workflow.

I think that would be easy to share the same config, though. For instance, you could have a webpack-module.js file containing the code you pasted. Then we could have a webpack.config.js file that would import this one… That’s a bit complex but that would work…

Cool, could you add a test that does that?

Copy link
Author

@jeroentervoorde jeroentervoorde Apr 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would work i guess. One problem is that the custom webpack file is copied to the target dir which. Therefore the 'module' config needs to be imported using an absolute path. ( I could just copy the module config to the target dir as well ofcourse)

Maybe a better approach would be to actually add a config setting for the module-config only. This can than be used for the reload workflow but also be automatically included in the generated webpack config. A custom config file would still need to manually include the module config but it would be located in the same directory where the custom file is copied.

I imported my custom config using
var modulesConfig = require('/home/.../project/js/webpack-reload.config.js')

modulesConfig.modules should than be merged with the configuration.

Is this the way to do it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could just copy the module config to the target dir as well of course

That’s what we do with the custom webpack config file.

Maybe a better approach would be to actually add a config setting for the module-config only.

I’m not sure about that. This configuration entry can contain arbitrary JavaScript expressions (for instance a JavaScript RegExp). Providing support for that would require some effort (unless we make it possible to write the configuration module in Scala.js). That’s why so far I tried to make as few configuration settings as possible available from scalajs-bundler: for other use cases you should fallback to a plain JavaScript config file.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually i meant a setting for the module config file that would replace the "webpackConfigFile in reloadWorkflow" i use now. This file can than be copied to target and used in reloadWorkflow and included in the generated webpack config (using require and maybe some js for merging the settings). Because it is copied it can also be included in a custom config using a relative filename.

…tion

- Added webpackSharedConfigFiles containing a list of files to be copied to the target dir.
- Copy reload config file to target dir so it can include a shared config using a relative path.
- Implement custom config for test runner (webpackConfigFile in test)
- Added sharedconfig scripted test.
@jeroentervoorde
Copy link
Author

I added a setting webpackSharedConfigFiles which contains a list of files copied to the webpack working dir. This file can than be included in a webpackCustomConfig file.

A test (sharedconfig) was added as a working example. While writing the test i noticed that the test runner also did not support a custom webpack file so i added this ("webpackCustomConfig in test") which can normally point to the same file as "webpackCustomConfig in webpackReload"

In the example the custom config file and the shared config could have been 1 file. In this case it would have been copied twice but i assume this is not a problem.

The pr needs more scaladoc. I'll add that if we agree on this implementation.

@julienrf
Copy link
Contributor

julienrf commented Apr 8, 2017

Hi, I think this is great! (and that would also probably solve #83)

However, I would propose the following change. Instead of having this sharedWebpackConfigFiles setting I would simply copy all the .js files that are in the baseDirectory. Actually, this should be configurable, so we would have a webpackResources setting of type PathFinder that would default to baseDirectory.value ** "*.js" (thus, that would include both the config files and the shared config files). Then we would copy all the webpackResources into the target directory before invoking webpack. What do you think? (Also, that might help us to fix #112)

If you could update the PR with that that would be awesome! (Then I might add some minor comments, but I would first like to validate the general solution)

@jeroentervoorde
Copy link
Author

Sure, i'll update it this week. My plan is to append the webpackConfigFile to the files returned by webpackResources as it may not be location in the project root. For #112 we could than hash over all these config files. Another option would be to enforce that webpackConfigFile is part of webpackResources but that's a bit more limiting.

The idea I had for the sharedWebpackConfigFiles was that it could be used as to implement merging in the generated config files as well (in a new PR). This can still be done but would still require a setting besides webpackResources.

@jeroentervoorde
Copy link
Author

Hi! Updated again. sharedWebpackConfigFiles -> webpackResources (using baseDirectory.value * "*.js" as default so only the files in the project root are copied)

webpackCustomConfig is copied as well if it wasn't by webpackResources.

@@ -6,6 +6,14 @@ import scalajsbundler.util.{Commands, JS}

object Webpack {

def copyToWorkingDir(targetDir: File)(file: File): File = {
val copy = targetDir / file.name
if (copy.getAbsolutePath != file.getAbsolutePath && !copy.exists()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these tests necessary? Does that happen to have the same source and destination? In such a case maybe we should let the IO.copyFile method throw an error. Also, the second test will make it impossible to update a file that has been copied and then changed afterwards. Unless I’m missing something?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your're right the first test isn't really necessary and the second is plain wrong (i was assuming an empty target dir). I removed them both.

val copy = targetDir / file.name
IO.copyFile(file, copy)
copy
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can’t you reuse the one defined in the Webpack object?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed that one.. Updated now

@@ -465,6 +502,10 @@ object ScalaJSBundlerPlugin extends AutoPlugin {
else webpackTask(fastOptJS)
}.value,

webpackReload in fastOptJS := Def.taskDyn {
ReloadWorkflowTasks.webpackTask(configuration.value, fastOptJS)
}.value,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a taskDyn rather than a task?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried changing it to a normal task but it doesn't compile. I assume because ReloadWorkflowTasks.webpackTask returns an Def.Initialize[Task[...]]

@@ -546,6 +587,24 @@ object ScalaJSBundlerPlugin extends AutoPlugin {
val sjsOutputName = sjsOutput.name.stripSuffix(".js")
val bundle = targetDir / s"$sjsOutputName-bundle.js"

val customWebpackConfigFile = (webpackConfigFile in test).value
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use the Test configuration instead of the test task?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed

Copy link
Contributor

@julienrf julienrf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That looks really great! Could you also add more documentation about which entries are required (which should not be present) when supplying a config file for tests or reload workflow?

// Use a different Webpack configuration file for reload workflow
webpackConfigFile in webpackReload := Some(baseDirectory.value / "reload.webpack.config.js")

webpackSharedConfigFiles := Seq(baseDirectory.value / "common.webpack.config.js")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not leave the default setting?

@dispalt
Copy link
Contributor

dispalt commented Apr 20, 2017

So just to understand this, does this allow us to have a webpack conf and still use the fast reload workflow?

@julienrf
Copy link
Contributor

test this please

@julienrf
Copy link
Contributor

@dispalt yes :)

@julienrf
Copy link
Contributor

@jeroentervoorde I pushed a commit to fix the tests. Could you please take into account my other remarks?

@scala-jenkins
Copy link
Collaborator

Refer to this link for build results (access rights to CI server needed):
https://scala-webapps.epfl.ch/jenkins//job/scalajs-bundler/126/
Test FAILed.

@julienrf
Copy link
Contributor

OK, I don’t know why but jenkins ignores my last push…

Updated documentation and sharedconfig test project
@julienrf
Copy link
Contributor

test this please

'image-webpack?bypassOnDebug&optimizationLevel=7&interlaced=false'
]
}
],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the CI (line 1170) it seems that at some point a require('fs') is performed from the browser… Do you know why? Do the tests run fine on your machine?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know. I ignored it because everything seems to run fine. I'll try to fix it tonight or tomorrow.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least the tests passed on the *nix CI. We have so many troubles with Windows support :(

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi. I fixed it using the additional "node" configuration described here:
pugjs/pug-loader#8

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, but that’s weird because the final target is the web browser, not node, right?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess so.. Is the target something i can/should change? I couldn't find it in the code.

Copy link
Contributor

@julienrf julienrf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excepted the error in the CI that looks awesome, thanks!

@scala-jenkins
Copy link
Collaborator

Refer to this link for build results (access rights to CI server needed):
https://scala-webapps.epfl.ch/jenkins//job/scalajs-bundler/128/
Test PASSed.

Here are the steps to share the loader configuration among your prod and dev config files. This
uses webpack-merge for convenience the same result could be accomplished using plain js only.

1. Put configuration it in a common.webpack.config.js file:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: extra “it”

Fixed documentation typo's
@julienrf julienrf merged commit a3d585b into scalacenter:master Apr 26, 2017
@julienrf
Copy link
Contributor

Thank you so much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants