mirror of https://github.com/webpack/webpack.git
feat: added `url` and `import` options for CSS
This commit is contained in:
parent
5e8317b881
commit
5e09d0e05f
|
@ -774,10 +774,18 @@ export type CssGeneratorExportsOnly = boolean;
|
|||
* Configure the generated local ident name.
|
||||
*/
|
||||
export type CssGeneratorLocalIdentName = string;
|
||||
/**
|
||||
* Enable/disable `@import` at-rules handling.
|
||||
*/
|
||||
export type CssParserImport = boolean;
|
||||
/**
|
||||
* Use ES modules named export for css exports.
|
||||
*/
|
||||
export type CssParserNamedExports = boolean;
|
||||
/**
|
||||
* Enable/disable `url()`/`image-set()`/`src()`/`image()` functions handling.
|
||||
*/
|
||||
export type CssParserUrl = boolean;
|
||||
/**
|
||||
* A Function returning a Promise resolving to a normalized entry.
|
||||
*/
|
||||
|
@ -2906,10 +2914,18 @@ export interface CssAutoGeneratorOptions {
|
|||
* Parser options for css/auto modules.
|
||||
*/
|
||||
export interface CssAutoParserOptions {
|
||||
/**
|
||||
* Enable/disable `@import` at-rules handling.
|
||||
*/
|
||||
import?: CssParserImport;
|
||||
/**
|
||||
* Use ES modules named export for css exports.
|
||||
*/
|
||||
namedExports?: CssParserNamedExports;
|
||||
/**
|
||||
* Enable/disable `url()`/`image-set()`/`src()`/`image()` functions handling.
|
||||
*/
|
||||
url?: CssParserUrl;
|
||||
}
|
||||
/**
|
||||
* Generator options for css modules.
|
||||
|
@ -2949,10 +2965,18 @@ export interface CssGlobalGeneratorOptions {
|
|||
* Parser options for css/global modules.
|
||||
*/
|
||||
export interface CssGlobalParserOptions {
|
||||
/**
|
||||
* Enable/disable `@import` at-rules handling.
|
||||
*/
|
||||
import?: CssParserImport;
|
||||
/**
|
||||
* Use ES modules named export for css exports.
|
||||
*/
|
||||
namedExports?: CssParserNamedExports;
|
||||
/**
|
||||
* Enable/disable `url()`/`image-set()`/`src()`/`image()` functions handling.
|
||||
*/
|
||||
url?: CssParserUrl;
|
||||
}
|
||||
/**
|
||||
* Generator options for css/module modules.
|
||||
|
@ -2979,19 +3003,35 @@ export interface CssModuleGeneratorOptions {
|
|||
* Parser options for css/module modules.
|
||||
*/
|
||||
export interface CssModuleParserOptions {
|
||||
/**
|
||||
* Enable/disable `@import` at-rules handling.
|
||||
*/
|
||||
import?: CssParserImport;
|
||||
/**
|
||||
* Use ES modules named export for css exports.
|
||||
*/
|
||||
namedExports?: CssParserNamedExports;
|
||||
/**
|
||||
* Enable/disable `url()`/`image-set()`/`src()`/`image()` functions handling.
|
||||
*/
|
||||
url?: CssParserUrl;
|
||||
}
|
||||
/**
|
||||
* Parser options for css modules.
|
||||
*/
|
||||
export interface CssParserOptions {
|
||||
/**
|
||||
* Enable/disable `@import` at-rules handling.
|
||||
*/
|
||||
import?: CssParserImport;
|
||||
/**
|
||||
* Use ES modules named export for css exports.
|
||||
*/
|
||||
namedExports?: CssParserNamedExports;
|
||||
/**
|
||||
* Enable/disable `url()`/`image-set()`/`src()`/`image()` functions handling.
|
||||
*/
|
||||
url?: CssParserUrl;
|
||||
}
|
||||
/**
|
||||
* No generator options are supported for this module type.
|
||||
|
|
|
@ -670,6 +670,8 @@ const applyModuleDefaults = (
|
|||
if (css) {
|
||||
F(module.parser, CSS_MODULE_TYPE, () => ({}));
|
||||
|
||||
D(module.parser[CSS_MODULE_TYPE], "import", true);
|
||||
D(module.parser[CSS_MODULE_TYPE], "url", true);
|
||||
D(module.parser[CSS_MODULE_TYPE], "namedExports", true);
|
||||
|
||||
F(module.generator, CSS_MODULE_TYPE, () => ({}));
|
||||
|
|
|
@ -293,26 +293,34 @@ class CssModulesPlugin {
|
|||
.for(type)
|
||||
.tap(PLUGIN_NAME, parserOptions => {
|
||||
validateParserOptions[type](parserOptions);
|
||||
const { namedExports } = parserOptions;
|
||||
const { url, import: importOption, namedExports } = parserOptions;
|
||||
|
||||
switch (type) {
|
||||
case CSS_MODULE_TYPE:
|
||||
return new CssParser({
|
||||
importOption,
|
||||
url,
|
||||
namedExports
|
||||
});
|
||||
case CSS_MODULE_TYPE_GLOBAL:
|
||||
return new CssParser({
|
||||
defaultMode: "global",
|
||||
importOption,
|
||||
url,
|
||||
namedExports
|
||||
});
|
||||
case CSS_MODULE_TYPE_MODULE:
|
||||
return new CssParser({
|
||||
defaultMode: "local",
|
||||
importOption,
|
||||
url,
|
||||
namedExports
|
||||
});
|
||||
case CSS_MODULE_TYPE_AUTO:
|
||||
return new CssParser({
|
||||
defaultMode: "auto",
|
||||
importOption,
|
||||
url,
|
||||
namedExports
|
||||
});
|
||||
}
|
||||
|
|
|
@ -148,12 +148,21 @@ const CSS_MODE_IN_BLOCK = 1;
|
|||
class CssParser extends Parser {
|
||||
/**
|
||||
* @param {object} options options
|
||||
* @param {boolean=} options.importOption need handle `@import`
|
||||
* @param {boolean=} options.url need handle URLs
|
||||
* @param {("pure" | "global" | "local" | "auto")=} options.defaultMode default mode
|
||||
* @param {boolean=} options.namedExports is named exports
|
||||
*/
|
||||
constructor({ defaultMode = "pure", namedExports = true } = {}) {
|
||||
constructor({
|
||||
defaultMode = "pure",
|
||||
importOption = true,
|
||||
url = true,
|
||||
namedExports = true
|
||||
} = {}) {
|
||||
super();
|
||||
this.defaultMode = defaultMode;
|
||||
this.import = importOption;
|
||||
this.url = url;
|
||||
this.namedExports = namedExports;
|
||||
/** @type {Comment[] | undefined} */
|
||||
this.comments = undefined;
|
||||
|
@ -289,6 +298,7 @@ class CssParser extends Parser {
|
|||
}
|
||||
return [pos, text.trimEnd()];
|
||||
};
|
||||
const eatSemi = walkCssTokens.eatUntil(";");
|
||||
const eatExportName = walkCssTokens.eatUntil(":};/");
|
||||
const eatExportValue = walkCssTokens.eatUntil("};/");
|
||||
/**
|
||||
|
@ -497,6 +507,10 @@ class CssParser extends Parser {
|
|||
return end;
|
||||
},
|
||||
url: (input, start, end, contentStart, contentEnd) => {
|
||||
if (!this.url) {
|
||||
return end;
|
||||
}
|
||||
|
||||
const { options, errors: commentErrors } = this.parseCommentOptions([
|
||||
lastTokenEndForComments,
|
||||
end
|
||||
|
@ -572,6 +586,10 @@ class CssParser extends Parser {
|
|||
return eatUntilSemi(input, start);
|
||||
}
|
||||
case "@import": {
|
||||
if (!this.import) {
|
||||
return eatSemi(input, end);
|
||||
}
|
||||
|
||||
if (!allowImportAtRule) {
|
||||
this._emitWarning(
|
||||
state,
|
||||
|
@ -901,6 +919,10 @@ class CssParser extends Parser {
|
|||
switch (name) {
|
||||
case "src":
|
||||
case "url": {
|
||||
if (!this.url) {
|
||||
return end;
|
||||
}
|
||||
|
||||
const string = walkCssTokens.eatString(input, end);
|
||||
if (!string) return end;
|
||||
const { options, errors: commentErrors } = this.parseCommentOptions(
|
||||
|
@ -955,7 +977,7 @@ class CssParser extends Parser {
|
|||
return string[1];
|
||||
}
|
||||
default: {
|
||||
if (IMAGE_SET_FUNCTION.test(name)) {
|
||||
if (this.url && IMAGE_SET_FUNCTION.test(name)) {
|
||||
lastTokenEndForComments = end;
|
||||
const values = walkCssTokens.eatImageSetStrings(input, end, {
|
||||
comment
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -395,8 +395,14 @@
|
|||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"import": {
|
||||
"$ref": "#/definitions/CssParserImport"
|
||||
},
|
||||
"namedExports": {
|
||||
"$ref": "#/definitions/CssParserNamedExports"
|
||||
},
|
||||
"url": {
|
||||
"$ref": "#/definitions/CssParserUrl"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -483,8 +489,14 @@
|
|||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"import": {
|
||||
"$ref": "#/definitions/CssParserImport"
|
||||
},
|
||||
"namedExports": {
|
||||
"$ref": "#/definitions/CssParserNamedExports"
|
||||
},
|
||||
"url": {
|
||||
"$ref": "#/definitions/CssParserUrl"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -516,11 +528,21 @@
|
|||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"import": {
|
||||
"$ref": "#/definitions/CssParserImport"
|
||||
},
|
||||
"namedExports": {
|
||||
"$ref": "#/definitions/CssParserNamedExports"
|
||||
},
|
||||
"url": {
|
||||
"$ref": "#/definitions/CssParserUrl"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CssParserImport": {
|
||||
"description": "Enable/disable `@import` at-rules handling.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"CssParserNamedExports": {
|
||||
"description": "Use ES modules named export for css exports.",
|
||||
"type": "boolean"
|
||||
|
@ -530,11 +552,21 @@
|
|||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"import": {
|
||||
"$ref": "#/definitions/CssParserImport"
|
||||
},
|
||||
"namedExports": {
|
||||
"$ref": "#/definitions/CssParserNamedExports"
|
||||
},
|
||||
"url": {
|
||||
"$ref": "#/definitions/CssParserUrl"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CssParserUrl": {
|
||||
"description": "Enable/disable `url()`/`image-set()`/`src()`/`image()` functions handling.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"Dependencies": {
|
||||
"description": "References to other configurations to depend on.",
|
||||
"type": "array",
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
* DO NOT MODIFY BY HAND.
|
||||
* Run `yarn special-lint-fix` to update
|
||||
*/
|
||||
"use strict";function r(t,{instancePath:a="",parentData:e,parentDataProperty:o,rootData:n=t}={}){if(!t||"object"!=typeof t||Array.isArray(t))return r.errors=[{params:{type:"object"}}],!1;{const a=0;for(const a in t)if("namedExports"!==a)return r.errors=[{params:{additionalProperty:a}}],!1;if(0===a&&void 0!==t.namedExports&&"boolean"!=typeof t.namedExports)return r.errors=[{params:{type:"boolean"}}],!1}return r.errors=null,!0}function t(a,{instancePath:e="",parentData:o,parentDataProperty:n,rootData:s=a}={}){let p=null,i=0;return r(a,{instancePath:e,parentData:o,parentDataProperty:n,rootData:s})||(p=null===p?r.errors:p.concat(r.errors),i=p.length),t.errors=p,0===i}module.exports=t,module.exports.default=t;
|
||||
"use strict";function r(t,{instancePath:e="",parentData:o,parentDataProperty:a,rootData:n=t}={}){if(!t||"object"!=typeof t||Array.isArray(t))return r.errors=[{params:{type:"object"}}],!1;{const e=0;for(const e in t)if("import"!==e&&"namedExports"!==e&&"url"!==e)return r.errors=[{params:{additionalProperty:e}}],!1;if(0===e){if(void 0!==t.import){const e=0;if("boolean"!=typeof t.import)return r.errors=[{params:{type:"boolean"}}],!1;var s=0===e}else s=!0;if(s){if(void 0!==t.namedExports){const e=0;if("boolean"!=typeof t.namedExports)return r.errors=[{params:{type:"boolean"}}],!1;s=0===e}else s=!0;if(s)if(void 0!==t.url){const e=0;if("boolean"!=typeof t.url)return r.errors=[{params:{type:"boolean"}}],!1;s=0===e}else s=!0}}}return r.errors=null,!0}function t(e,{instancePath:o="",parentData:a,parentDataProperty:n,rootData:s=e}={}){let p=null,i=0;return r(e,{instancePath:o,parentData:a,parentDataProperty:n,rootData:s})||(p=null===p?r.errors:p.concat(r.errors),i=p.length),t.errors=p,0===i}module.exports=t,module.exports.default=t;
|
|
@ -3,4 +3,4 @@
|
|||
* DO NOT MODIFY BY HAND.
|
||||
* Run `yarn special-lint-fix` to update
|
||||
*/
|
||||
"use strict";function r(t,{instancePath:a="",parentData:e,parentDataProperty:o,rootData:n=t}={}){if(!t||"object"!=typeof t||Array.isArray(t))return r.errors=[{params:{type:"object"}}],!1;{const a=0;for(const a in t)if("namedExports"!==a)return r.errors=[{params:{additionalProperty:a}}],!1;if(0===a&&void 0!==t.namedExports&&"boolean"!=typeof t.namedExports)return r.errors=[{params:{type:"boolean"}}],!1}return r.errors=null,!0}function t(a,{instancePath:e="",parentData:o,parentDataProperty:n,rootData:s=a}={}){let p=null,i=0;return r(a,{instancePath:e,parentData:o,parentDataProperty:n,rootData:s})||(p=null===p?r.errors:p.concat(r.errors),i=p.length),t.errors=p,0===i}module.exports=t,module.exports.default=t;
|
||||
"use strict";function r(t,{instancePath:e="",parentData:o,parentDataProperty:a,rootData:n=t}={}){if(!t||"object"!=typeof t||Array.isArray(t))return r.errors=[{params:{type:"object"}}],!1;{const e=0;for(const e in t)if("import"!==e&&"namedExports"!==e&&"url"!==e)return r.errors=[{params:{additionalProperty:e}}],!1;if(0===e){if(void 0!==t.import){const e=0;if("boolean"!=typeof t.import)return r.errors=[{params:{type:"boolean"}}],!1;var s=0===e}else s=!0;if(s){if(void 0!==t.namedExports){const e=0;if("boolean"!=typeof t.namedExports)return r.errors=[{params:{type:"boolean"}}],!1;s=0===e}else s=!0;if(s)if(void 0!==t.url){const e=0;if("boolean"!=typeof t.url)return r.errors=[{params:{type:"boolean"}}],!1;s=0===e}else s=!0}}}return r.errors=null,!0}function t(e,{instancePath:o="",parentData:a,parentDataProperty:n,rootData:s=e}={}){let p=null,i=0;return r(e,{instancePath:o,parentData:a,parentDataProperty:n,rootData:s})||(p=null===p?r.errors:p.concat(r.errors),i=p.length),t.errors=p,0===i}module.exports=t,module.exports.default=t;
|
|
@ -3,4 +3,4 @@
|
|||
* DO NOT MODIFY BY HAND.
|
||||
* Run `yarn special-lint-fix` to update
|
||||
*/
|
||||
"use strict";function r(t,{instancePath:a="",parentData:e,parentDataProperty:o,rootData:n=t}={}){if(!t||"object"!=typeof t||Array.isArray(t))return r.errors=[{params:{type:"object"}}],!1;{const a=0;for(const a in t)if("namedExports"!==a)return r.errors=[{params:{additionalProperty:a}}],!1;if(0===a&&void 0!==t.namedExports&&"boolean"!=typeof t.namedExports)return r.errors=[{params:{type:"boolean"}}],!1}return r.errors=null,!0}function t(a,{instancePath:e="",parentData:o,parentDataProperty:n,rootData:s=a}={}){let p=null,i=0;return r(a,{instancePath:e,parentData:o,parentDataProperty:n,rootData:s})||(p=null===p?r.errors:p.concat(r.errors),i=p.length),t.errors=p,0===i}module.exports=t,module.exports.default=t;
|
||||
"use strict";function r(t,{instancePath:e="",parentData:o,parentDataProperty:a,rootData:n=t}={}){if(!t||"object"!=typeof t||Array.isArray(t))return r.errors=[{params:{type:"object"}}],!1;{const e=0;for(const e in t)if("import"!==e&&"namedExports"!==e&&"url"!==e)return r.errors=[{params:{additionalProperty:e}}],!1;if(0===e){if(void 0!==t.import){const e=0;if("boolean"!=typeof t.import)return r.errors=[{params:{type:"boolean"}}],!1;var s=0===e}else s=!0;if(s){if(void 0!==t.namedExports){const e=0;if("boolean"!=typeof t.namedExports)return r.errors=[{params:{type:"boolean"}}],!1;s=0===e}else s=!0;if(s)if(void 0!==t.url){const e=0;if("boolean"!=typeof t.url)return r.errors=[{params:{type:"boolean"}}],!1;s=0===e}else s=!0}}}return r.errors=null,!0}function t(e,{instancePath:o="",parentData:a,parentDataProperty:n,rootData:s=e}={}){let p=null,i=0;return r(e,{instancePath:o,parentData:a,parentDataProperty:n,rootData:s})||(p=null===p?r.errors:p.concat(r.errors),i=p.length),t.errors=p,0===i}module.exports=t,module.exports.default=t;
|
|
@ -3,4 +3,4 @@
|
|||
* DO NOT MODIFY BY HAND.
|
||||
* Run `yarn special-lint-fix` to update
|
||||
*/
|
||||
"use strict";function r(t,{instancePath:a="",parentData:e,parentDataProperty:o,rootData:n=t}={}){if(!t||"object"!=typeof t||Array.isArray(t))return r.errors=[{params:{type:"object"}}],!1;{const a=0;for(const a in t)if("namedExports"!==a)return r.errors=[{params:{additionalProperty:a}}],!1;if(0===a&&void 0!==t.namedExports&&"boolean"!=typeof t.namedExports)return r.errors=[{params:{type:"boolean"}}],!1}return r.errors=null,!0}function t(a,{instancePath:e="",parentData:o,parentDataProperty:n,rootData:s=a}={}){let p=null,i=0;return r(a,{instancePath:e,parentData:o,parentDataProperty:n,rootData:s})||(p=null===p?r.errors:p.concat(r.errors),i=p.length),t.errors=p,0===i}module.exports=t,module.exports.default=t;
|
||||
"use strict";function r(t,{instancePath:e="",parentData:o,parentDataProperty:a,rootData:n=t}={}){if(!t||"object"!=typeof t||Array.isArray(t))return r.errors=[{params:{type:"object"}}],!1;{const e=0;for(const e in t)if("import"!==e&&"namedExports"!==e&&"url"!==e)return r.errors=[{params:{additionalProperty:e}}],!1;if(0===e){if(void 0!==t.import){const e=0;if("boolean"!=typeof t.import)return r.errors=[{params:{type:"boolean"}}],!1;var s=0===e}else s=!0;if(s){if(void 0!==t.namedExports){const e=0;if("boolean"!=typeof t.namedExports)return r.errors=[{params:{type:"boolean"}}],!1;s=0===e}else s=!0;if(s)if(void 0!==t.url){const e=0;if("boolean"!=typeof t.url)return r.errors=[{params:{type:"boolean"}}],!1;s=0===e}else s=!0}}}return r.errors=null,!0}function t(e,{instancePath:o="",parentData:a,parentDataProperty:n,rootData:s=e}={}){let p=null,i=0;return r(e,{instancePath:o,parentData:a,parentDataProperty:n,rootData:s})||(p=null===p?r.errors:p.concat(r.errors),i=p.length),t.errors=p,0===i}module.exports=t,module.exports.default=t;
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,4 +1,4 @@
|
|||
@import url(https://test.cases/path/../../../../configCases/css/css-import/external.css);
|
||||
@import url(https://test.cases/path/../../../../configCases/css/import/external.css);
|
||||
@import "style-imported.css";
|
||||
body {
|
||||
background: red;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import url(https://test.cases/path/../../../../configCases/css/css-import/external.css);
|
||||
@import url(https://test.cases/path/../../../../configCases/css/import/external.css);
|
||||
@import "style-imported.css";
|
||||
body {
|
||||
background: red;
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
/** @type {import("../../../../").Configuration} */
|
||||
module.exports = {
|
||||
target: "web",
|
||||
mode: "development",
|
||||
experiments: {
|
||||
css: true
|
||||
},
|
||||
resolve: {
|
||||
byDependency: {
|
||||
"css-import": {
|
||||
conditionNames: ["custom-name", "..."],
|
||||
extensions: [".mycss", "..."]
|
||||
}
|
||||
}
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.mycss$/,
|
||||
loader: "./string-loader",
|
||||
type: "css/global"
|
||||
},
|
||||
{
|
||||
test: /\.less$/,
|
||||
loader: "less-loader",
|
||||
type: "css/global"
|
||||
}
|
||||
]
|
||||
},
|
||||
externals: {
|
||||
"external-1.css": "css-import external-1.css",
|
||||
"external-2.css": "css-import external-2.css",
|
||||
"external-3.css": "css-import external-3.css",
|
||||
"external-4.css": "css-import external-4.css",
|
||||
"external-5.css": "css-import external-5.css",
|
||||
"external-6.css": "css-import external-6.css",
|
||||
"external-7.css": "css-import external-7.css",
|
||||
"external-8.css": "css-import external-8.css",
|
||||
"external-9.css": "css-import external-9.css",
|
||||
"external-10.css": "css-import external-10.css",
|
||||
"external-11.css": "css-import external-11.css",
|
||||
"external-12.css": "css-import external-12.css",
|
||||
"external-13.css": "css-import external-13.css",
|
||||
"external-14.css": "css-import external-14.css"
|
||||
}
|
||||
};
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
|
@ -60,8 +60,8 @@ style2.css?foo=9
|
|||
@import url(style2.css) screen and (orientation:landscape);
|
||||
@import url(style2.css) screen and (orientation:landscape);
|
||||
@import url(style2.css) (min-width: 100px);
|
||||
@import url(https://test.cases/path/../../../../configCases/css/css-import/external.css);
|
||||
@import url(https://test.cases/path/../../../../configCases/css/css-import/external.css) screen and (orientation:landscape);
|
||||
@import url(https://test.cases/path/../../../../configCases/css/import/external.css);
|
||||
@import url(https://test.cases/path/../../../../configCases/css/import/external.css) screen and (orientation:landscape);
|
||||
@import "//example.com/style.css";
|
||||
@import url('test.css?foo=1&bar=1');
|
||||
@import url('style2.css?foo=1&bar=1#hash');
|
|
@ -1,5 +1,5 @@
|
|||
@import url(./style11.css);
|
||||
@import url(https://test.cases/path/../../../../configCases/css/css-import/external1.css);
|
||||
@import url(https://test.cases/path/../../../../configCases/css/import/external1.css);
|
||||
@import url(./style12.css);
|
||||
@import url(./style13.css);
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
@import url(https://test.cases/path/../../../../configCases/css/css-import/external2.css);
|
||||
@import url(https://test.cases/path/../../../../configCases/css/import/external2.css);
|
||||
|
||||
.style12 {
|
||||
color: red;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue