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

BREAKING CHANGES: create static option and remove replaced options #2670

Merged
merged 35 commits into from
Aug 18, 2020

Conversation

knagaitsev
Copy link
Collaborator

  • This is a bugfix
  • This is a feature
  • This is a code refactor
  • This is a test update
  • This is a docs update
  • This is a metadata update

For Bugs and Features; did you add new tests?

Not yet

Motivation / Use-Case

static option is replacing many existing options. See options.json.

Breaking Changes

  • Remove contentBase, contentBasePublicPath, serveIndex, staticOptions, watchContentBase, watchOptions in favor of static
  • API changes related to contentBase

Additional Info

@codecov
Copy link

codecov bot commented Jul 4, 2020

Codecov Report

Merging #2670 into v4 will increase coverage by 0.02%.
The diff coverage is 98.57%.

Impacted file tree graph

@@            Coverage Diff             @@
##               v4    #2670      +/-   ##
==========================================
+ Coverage   92.85%   92.88%   +0.02%     
==========================================
  Files          37       37              
  Lines        1316     1293      -23     
  Branches      354      344      -10     
==========================================
- Hits         1222     1201      -21     
+ Misses         89       88       -1     
+ Partials        5        4       -1     
Impacted Files Coverage Δ
lib/Server.js 96.33% <96.87%> (+0.35%) ⬆️
lib/utils/createConfig.js 95.45% <100.00%> (+0.85%) ⬆️
lib/utils/normalizeOptions.js 100.00% <100.00%> (ø)
lib/utils/status.js 80.00% <0.00%> (-10.00%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2bbd36f...30b3aca. Read the comment docs.

@knagaitsev
Copy link
Collaborator Author

@evilebottnawi Do we need directory to be a required property for the static object option? There is a chance the user could want to set other static options and keep directory as the default current working directory.

lib/options.json Outdated
"minLength": 1
},
{
"type": "object"
Copy link
Member

Choose a reason for hiding this comment

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

Let's create definition fro object notation and use here it

Copy link
Member

Choose a reason for hiding this comment

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

Example:

"anyOf": [
        {
          "type": "boolean"
        },
        {
          "$ref": "#/definitions/StaticString"
        },
        {
          "$ref": "#/definitions/StaticObject"
        },
        {
          "type": "array",
          "items": {
            "anyOf": [
              {
                "$ref": "#/definitions/StaticString"
              },
              {
                "$ref": "#/definitions/StaticObject"
              }
            ]
          },
          "minItems": 1
        }
      ]

) {
options.static.watch = {};
}
}
Copy link
Member

@alexander-akait alexander-akait Jul 6, 2020

Choose a reason for hiding this comment

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

I think like this:

const defaultOptionsForStatic = {
    directory: process.cwd(),
    staticOptions: {},
    publicPath: ['/'],
    serveIndex: { icons: true },
    // Respect options from compiler.watchOptions
    watch: {
      // ...
    },
  };

if (options.static === 'undefined') {
    options.static = [{ defaultOptionsForStatic }];
  } else if (typeof options.static === 'boolean') {
    options.static = options.static ? [defaultOptionsForStatic] : false;
  } else if (typeof options.static === 'string') {
    options.static = [
      { ...defaultOptionsForStatic, directory: options.static },
    ];
  } else if (Array.isArray(options.static)) {
    options.static = options.static.map((item) => {
      if (typeof item === 'string') {
        return { ...defaultOptionsForStatic, directory: item };
      }

      return { ...defaultOptionsForStatic, ...item };
    });
  } else {
    options.static = [{ ...defaultOptionsForStatic, ...options.static }];
  }

Note - we should support --no-static for CLI

bin/cli-flags.js Outdated
type: Boolean,
describe: 'Enable live-reloading of the content-base.',
describe: 'Enable live-reloading of the static directory.',
Copy link
Member

@alexander-akait alexander-akait Jul 7, 2020

Choose a reason for hiding this comment

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

I think we should not provide here a lot of stuff, --static=path/to/directory and --no-static are enough, for other complex examples you need to use the configuration

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

So we will get rid of the serve-index CLI flag?

Copy link
Collaborator Author

@knagaitsev knagaitsev Aug 3, 2020

Choose a reason for hiding this comment

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

Also, it seems our CLI system does not work well with a no-static flag, since static would have to be a string flag, not sure how to work around it without a hacky method

Edit: Never mind, I think I figured it out

lib/Server.js Outdated
}

if (staticOption.watch) {
this._watch(staticOption.directory, staticOption.watch);
Copy link
Member

Choose a reason for hiding this comment

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

Let's rename _watch to watchFiles

const watchOptions = watchOptionsConfig
? watchOptionsConfig.watchOptions
: {};
console.log(compiler.options.watch);
Copy link
Member

Choose a reason for hiding this comment

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

console.log

@knagaitsev knagaitsev force-pushed the chore/static-option branch from a4e11f0 to 5caa38b Compare July 7, 2020 15:59
@knagaitsev knagaitsev mentioned this pull request Jul 13, 2020
6 tasks
@knagaitsev knagaitsev force-pushed the chore/static-option branch from 5caa38b to f5597e4 Compare July 23, 2020 05:17
@knagaitsev knagaitsev force-pushed the chore/static-option branch from e3ef515 to 497f35d Compare August 2, 2020 15:56
}
});
it('Should throw exception (number)', (done) => {
it('Should throw exception (external url)', (done) => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@evilebottnawi Is it correct that I should be throwing if isAbsoluteUrl for the static option is true?

Copy link
Member

Choose a reason for hiding this comment

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

No sure, I think we should improve it on schema-utils side, and support only paths, no URLs

lib/options.json Outdated
]
}
},
"required": ["directory"]
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Do we need this to be required? It seems unnecessary and may be confusing if the user is just specifying watch options or something.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm going to remove this and let it default to process.cwd() as usual if not provided, unless you think it is needed

Copy link
Member

Choose a reason for hiding this comment

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

Yep, you are right, we don't need it, because you can set only watchOptions

@@ -75,16 +70,11 @@ const options = {
group: SSL_GROUP,
describe: 'HTTP/2, must be used with HTTPS',
},
'static-directory': {
static: {
Copy link
Member

Choose a reason for hiding this comment

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

Can be multiple

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@evilebottnawi Like --static=example/dir1,example/dir2?

Copy link
Member

Choose a reason for hiding this comment

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

Like --static=example/dir1 --static=example/dir2

@knagaitsev
Copy link
Collaborator Author

I'm getting System limit for number of file watchers reached error repeatedly if I do npm run test, though individual tests seem to be fine. Does it look like I'm doing anything wrong with opening or closing the watcher?

@alexander-akait
Copy link
Member

We need to set https://github.com/paulmillr/chokidar/blob/master/index.js#L325 to true for tests, to avoid it

lib/Server.js Outdated
if (this.options.watchContentBase) {
runnableFeatures.push('watchContentBase');
if (this.options.static) {
runnableFeatures.push('serveIndex', 'watchStatic');
Copy link
Member

@alexander-akait alexander-akait Aug 4, 2020

Choose a reason for hiding this comment

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

I think we can union static/serveIndex/watchStatic in one method and static middleware, using one without the other doesn't make sense at all

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@evilebottnawi I tried that but it causes breaking changes when historyApiFallback is enabled. It seems that the order of middleware things that are enabled surrounding historyApiFallback is important

https://github.com/webpack/webpack-dev-server/blob/master/lib/Server.js#L554-L575

Copy link
Member

@alexander-akait alexander-akait Aug 4, 2020

Choose a reason for hiding this comment

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

Why do not put static feature after historyApiFallback, or maybe we should union historyApiFallback with static features?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think it makes sense to add it to static since it deals with serving static HTML content

Copy link
Member

Choose a reason for hiding this comment

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

Yep, i think we should add the historyApiFallback option to static

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@evilebottnawi After some searching I figured out that contentBaseFiles (

runnableFeatures.push('contentBaseFiles');
) feature was placed before and after historyApiFallback for this reason:

https://github.com/bripkens/connect-history-api-fallback/blob/master/examples/static-files-and-index-rewrite/README.md#configuring-the-middleware

Is it possible that the middleware feature is added multiple times for a similar reason? Changing it so that there is only 1 middleware pushed does not seem to break any tests, but maybe tests were not made for it?

Copy link
Collaborator Author

@knagaitsev knagaitsev Aug 17, 2020

Choose a reason for hiding this comment

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

I think I will not mess with the middleware runnable feature, but will investigate it later and see if I can add some tests for having it get pushed multiple times.

I have made the 3 features: static, serveIndex, and watchStatic. It would be ideal to have only the static feature, but it is complicated by the historyApiFallback feature so having 3 features is the easiest solution at the moment

Copy link
Member

Choose a reason for hiding this comment

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

It is very weird, because if we can't find something in static and history we should return 404, not trying to do it again 😕 maybe I something don't understand

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@evilebottnawi It isn't a matter of finding something or returning a 404, but rather the priority of static vs history when they are both trying to serve something from the same path. I still don't know exactly why it works, but placing static middleware before and after seems to ensure that static files take priority over the history api fallback file.

Copy link
Member

Choose a reason for hiding this comment

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

Yep, I see, very weird, but we can't do something here 😞

@alexander-akait
Copy link
Member

/cc @hiroppy @Loonride But I am fine with merge it

/cc @Loonride Can we open new issue about history and static weird problem and resolve it in future

lib/Server.js Outdated
this.setupStaticFeature();
},
// Todo rename to `serveIndex` in future major release
contentBaseIndex: () => {
serveIndex: () => {
Copy link
Member

Choose a reason for hiding this comment

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

staticServeIndex

Copy link
Member

Choose a reason for hiding this comment

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

and this.setupStaticServeIndexFeature

lib/Server.js Outdated
this.setupServeIndexFeature();
},
// Todo rename to `watchStatic` in future major release
watchContentBase: () => {
watchStatic: () => {
Copy link
Member

Choose a reason for hiding this comment

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

staticWatch

Copy link
Member

Choose a reason for hiding this comment

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

and this.setupStaticWatchFeature

@knagaitsev knagaitsev changed the title WIP: create static option and remove replaced options BREAKING CHANGES: create static option and remove replaced options Aug 17, 2020
Copy link
Member

@alexander-akait alexander-akait left a comment

Choose a reason for hiding this comment

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

To keep static name feature consistently

lib/Server.js Outdated
@@ -382,10 +382,10 @@ class Server {
static: () => {
this.setupStaticFeature();
},
serveIndex: () => {
staticServeIndex: () => {
this.setupServeIndexFeature();
Copy link
Member

Choose a reason for hiding this comment

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

And let's rename method names: this.setupStaticServeIndexFeature, as I written above 🥇

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

And let's rename method names: this.setupStaticServeIndexFeature, as I written above

Just did that 👍

Copy link
Member

@alexander-akait alexander-akait left a comment

Choose a reason for hiding this comment

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

/cc @hiroppy

Feel free to merge after CI will be green

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.

3 participants