diff --git a/.gitignore b/.gitignore index d81a67f1..9c22fc5a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,9 @@ npm-debug.log* /local /reports /node_modules +/test/fixtures/import/import-absolute.css +/test/fixtures/url/url-absolute.css +/test/fixtures/modules/composes/composes-absolute.css .DS_Store Thumbs.db diff --git a/src/utils.js b/src/utils.js index f47773ea..581aec8e 100644 --- a/src/utils.js +++ b/src/utils.js @@ -73,6 +73,10 @@ function defaultGetLocalIdent( } function normalizeUrl(url, isStringValue) { + if (matchNativeWin32Path.test(url)) { + return url; + } + let normalizedUrl = url; if (isStringValue && /\\[\n]/.test(normalizedUrl)) { @@ -509,11 +513,6 @@ async function resolveRequests(resolve, context, possibleRequests) { } function isUrlRequestable(url) { - // Windows absolute paths - if (matchNativeWin32Path.test(url)) { - return false; - } - // Protocol-relative URLs if (/^\/\//.test(url)) { return false; @@ -525,7 +524,7 @@ function isUrlRequestable(url) { } // Absolute URLs - if (/^[a-z][a-z0-9+.-]*:/i.test(url)) { + if (/^[a-z][a-z0-9+.-]*:/i.test(url) && !matchNativeWin32Path.test(url)) { return false; } diff --git a/test/__snapshots__/import-option.test.js.snap b/test/__snapshots__/import-option.test.js.snap index fd5cb49c..faa16ec1 100644 --- a/test/__snapshots__/import-option.test.js.snap +++ b/test/__snapshots__/import-option.test.js.snap @@ -152,6 +152,41 @@ Array [ exports[`"import" option should keep original order: warnings 1`] = `Array []`; +exports[`"import" option should resolve absolute path: errors 1`] = `Array []`; + +exports[`"import" option should resolve absolute path: module 1`] = ` +"// Imports +import ___CSS_LOADER_API_IMPORT___ from \\"../../../src/runtime/api.js\\"; +import ___CSS_LOADER_AT_RULE_IMPORT_0___ from \\"-!../../../src/index.js??[ident]!./test.css\\"; +var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(false); +___CSS_LOADER_EXPORT___.i(___CSS_LOADER_AT_RULE_IMPORT_0___); +// Module +___CSS_LOADER_EXPORT___.push([module.id, \\"\\", \\"\\"]); +// Exports +export default ___CSS_LOADER_EXPORT___; +" +`; + +exports[`"import" option should resolve absolute path: result 1`] = ` +Array [ + Array [ + "../../src/index.js?[ident]!./import/test.css", + ".test { + a: a; +} +", + "", + ], + Array [ + "./import/import-absolute.css", + "", + "", + ], +] +`; + +exports[`"import" option should resolve absolute path: warnings 1`] = `Array []`; + exports[`"import" option should resolve server-relative url relative rootContext: errors 1`] = `Array []`; exports[`"import" option should resolve server-relative url relative rootContext: module 1`] = ` diff --git a/test/__snapshots__/modules-option.test.js.snap b/test/__snapshots__/modules-option.test.js.snap index c0ed06df..353654e5 100644 --- a/test/__snapshots__/modules-option.test.js.snap +++ b/test/__snapshots__/modules-option.test.js.snap @@ -668,6 +668,44 @@ Array [ exports[`"modules" option should keep order: warnings 1`] = `Array []`; +exports[`"modules" option should resolve absolute path in composes: errors 1`] = `Array []`; + +exports[`"modules" option should resolve absolute path in composes: module 1`] = ` +"// Imports +import ___CSS_LOADER_API_IMPORT___ from \\"../../../../src/runtime/api.js\\"; +import ___CSS_LOADER_ICSS_IMPORT_0___ from \\"-!../../../../src/index.js??[ident]!./imported-simple.css\\"; +var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(false); +___CSS_LOADER_EXPORT___.i(___CSS_LOADER_ICSS_IMPORT_0___, \\"\\", true); +// Module +___CSS_LOADER_EXPORT___.push([module.id, \\"._2Qa8f_r4FS0cuNEBSCJGHl { color: red; }\\", \\"\\"]); +// Exports +___CSS_LOADER_EXPORT___.locals = { + \\"simple\\": \\"_2Qa8f_r4FS0cuNEBSCJGHl \\" + ___CSS_LOADER_ICSS_IMPORT_0___.locals[\\"imported-simple\\"] + \\"\\" +}; +export default ___CSS_LOADER_EXPORT___; +" +`; + +exports[`"modules" option should resolve absolute path in composes: result 1`] = ` +Array [ + Array [ + "../../src/index.js?[ident]!./modules/composes/imported-simple.css", + "._1LcKtmpK51ikm2OTXu6tSg { + display: block; +} +", + "", + ], + Array [ + "./modules/composes/composes-absolute.css", + "._2Qa8f_r4FS0cuNEBSCJGHl { color: red; }", + "", + ], +] +`; + +exports[`"modules" option should resolve absolute path in composes: warnings 1`] = `Array []`; + exports[`"modules" option should resolve package from node_modules with and without tilde: errors 1`] = `Array []`; exports[`"modules" option should resolve package from node_modules with and without tilde: module 1`] = ` diff --git a/test/__snapshots__/url-option.test.js.snap b/test/__snapshots__/url-option.test.js.snap index 95788659..50d8f1d6 100644 --- a/test/__snapshots__/url-option.test.js.snap +++ b/test/__snapshots__/url-option.test.js.snap @@ -1,5 +1,34 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`"url" option should resolve absolute path: errors 1`] = `Array []`; + +exports[`"url" option should resolve absolute path: module 1`] = ` +"// Imports +import ___CSS_LOADER_API_IMPORT___ from \\"../../../src/runtime/api.js\\"; +import ___CSS_LOADER_GET_URL_IMPORT___ from \\"../../../src/runtime/getUrl.js\\"; +import ___CSS_LOADER_URL_IMPORT_0___ from \\"./img.png\\"; +var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(false); +var ___CSS_LOADER_URL_REPLACEMENT_0___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_0___); +// Module +___CSS_LOADER_EXPORT___.push([module.id, \\"\\\\n.background {background: url(\\" + ___CSS_LOADER_URL_REPLACEMENT_0___ + \\"); }\\", \\"\\"]); +// Exports +export default ___CSS_LOADER_EXPORT___; +" +`; + +exports[`"url" option should resolve absolute path: result 1`] = ` +Array [ + Array [ + "./url/url-absolute.css", + " +.background {background: url(/webpack/public/path/img.png); }", + "", + ], +] +`; + +exports[`"url" option should resolve absolute path: warnings 1`] = `Array []`; + exports[`"url" option should throw an error on unresolved import: errors 1`] = ` Array [ "ModuleBuildError: Module build failed (from \`replaced original path\`): diff --git a/test/fixtures/import/import-absolute.js b/test/fixtures/import/import-absolute.js new file mode 100644 index 00000000..c599c6dd --- /dev/null +++ b/test/fixtures/import/import-absolute.js @@ -0,0 +1,5 @@ +import css from './import-absolute.css'; + +__export__ = css; + +export default css; diff --git a/test/fixtures/modules/composes/composes-absolute.js b/test/fixtures/modules/composes/composes-absolute.js new file mode 100644 index 00000000..1b76bb2b --- /dev/null +++ b/test/fixtures/modules/composes/composes-absolute.js @@ -0,0 +1,5 @@ +import css from './composes-absolute.css'; + +__export__ = css; + +export default css; diff --git a/test/fixtures/url/url-absolute.js b/test/fixtures/url/url-absolute.js new file mode 100644 index 00000000..536ef32c --- /dev/null +++ b/test/fixtures/url/url-absolute.js @@ -0,0 +1,5 @@ +import css from './url-absolute.css'; + +__export__ = css; + +export default css; diff --git a/test/import-option.test.js b/test/import-option.test.js index 6a154754..7388dbc8 100644 --- a/test/import-option.test.js +++ b/test/import-option.test.js @@ -1,3 +1,6 @@ +import fs from 'fs'; +import path from 'path'; + import { compile, getCompiler, @@ -149,6 +152,27 @@ describe('"import" option', () => { expect(getErrors(stats)).toMatchSnapshot('errors'); }); + it('should resolve absolute path', async () => { + // Create the file with absolute path + const fileDirectory = path.resolve(__dirname, 'fixtures', 'import'); + const file = path.resolve(fileDirectory, 'import-absolute.css'); + const absolutePath = path.resolve(fileDirectory, 'test.css'); + + fs.writeFileSync(file, `@import "${absolutePath}";`); + + const compiler = getCompiler('./import/import-absolute.js'); + const stats = await compile(compiler); + + expect( + getModuleSource('./import/import-absolute.css', stats) + ).toMatchSnapshot('module'); + expect(getExecutedCode('main.bundle.js', compiler, stats)).toMatchSnapshot( + 'result' + ); + expect(getWarnings(stats)).toMatchSnapshot('warnings'); + expect(getErrors(stats)).toMatchSnapshot('errors'); + }); + it('should throw an error on unresolved import', async () => { const compiler = getCompiler('./import/unresolved.js'); const stats = await compile(compiler); diff --git a/test/modules-option.test.js b/test/modules-option.test.js index 0de057a1..cf0e8074 100644 --- a/test/modules-option.test.js +++ b/test/modules-option.test.js @@ -309,6 +309,37 @@ describe('"modules" option', () => { expect(getErrors(stats)).toMatchSnapshot('errors'); }); + it('should resolve absolute path in composes', async () => { + // Create the file with absolute path + const fileDirectory = path.resolve( + __dirname, + 'fixtures', + 'modules', + 'composes' + ); + const file = path.resolve(fileDirectory, 'composes-absolute.css'); + const absolutePath = path.resolve(fileDirectory, 'imported-simple.css'); + + fs.writeFileSync( + file, + `.simple { color: red; composes: imported-simple from '${absolutePath}'; }` + ); + + const compiler = getCompiler('./modules/composes/composes-absolute.js', { + modules: true, + }); + const stats = await compile(compiler); + + expect( + getModuleSource('./modules/composes/composes-absolute.css', stats) + ).toMatchSnapshot('module'); + expect(getExecutedCode('main.bundle.js', compiler, stats)).toMatchSnapshot( + 'result' + ); + expect(getWarnings(stats)).toMatchSnapshot('warnings'); + expect(getErrors(stats)).toMatchSnapshot('errors'); + }); + it('should support resolving in composes preprocessor files with extensions', async () => { const compiler = getCompiler( './modules/composes/composes-preprocessors.js', diff --git a/test/url-option.test.js b/test/url-option.test.js index bdfbcaf5..d54d3016 100644 --- a/test/url-option.test.js +++ b/test/url-option.test.js @@ -1,3 +1,6 @@ +import fs from 'fs'; +import path from 'path'; + import { compile, getCompiler, @@ -67,6 +70,29 @@ describe('"url" option', () => { expect(getErrors(stats)).toMatchSnapshot('errors'); }); + it('should resolve absolute path', async () => { + // Create the file with absolute path + const fileDirectory = path.resolve(__dirname, 'fixtures', 'url'); + const file = path.resolve(fileDirectory, 'url-absolute.css'); + const absolutePath = path.resolve(fileDirectory, 'img.png'); + + const code = `\n.background {background: url(${absolutePath}); }`; + + fs.writeFileSync(file, code); + + const compiler = getCompiler('./url/url-absolute.js'); + const stats = await compile(compiler); + + expect(getModuleSource('./url/url-absolute.css', stats)).toMatchSnapshot( + 'module' + ); + expect(getExecutedCode('main.bundle.js', compiler, stats)).toMatchSnapshot( + 'result' + ); + expect(getWarnings(stats)).toMatchSnapshot('warnings'); + expect(getErrors(stats)).toMatchSnapshot('errors'); + }); + it('should throw an error on unresolved import', async () => { const compiler = getCompiler('./url/url-unresolved.js'); const stats = await compile(compiler);