@@ -31,9 +31,7 @@ function createWebpackConfig(outputDirName = '', command, argv = {}) {
31
31
}
32
32
33
33
function convertToManifestPath ( assetSrc , webpackConfig ) {
34
- const manifestData = JSON . parse (
35
- fs . readFileSync ( path . join ( webpackConfig . outputPath , 'manifest.json' ) , 'utf8' )
36
- ) ;
34
+ const manifestData = JSON . parse ( readOutputFileContents ( 'manifest.json' , webpackConfig ) ) ;
37
35
38
36
if ( typeof manifestData [ assetSrc ] === 'undefined' ) {
39
37
throw new Error ( `Path ${ assetSrc } not found in manifest!` ) ;
@@ -42,6 +40,26 @@ function convertToManifestPath(assetSrc, webpackConfig) {
42
40
return manifestData [ assetSrc ] ;
43
41
}
44
42
43
+ function readOutputFileContents ( filename , config ) {
44
+ const fullPath = path . join ( config . outputPath , filename ) ;
45
+
46
+ if ( ! fs . existsSync ( fullPath ) ) {
47
+ throw new Error ( `Output file "${ filename } " does not exist.` ) ;
48
+ }
49
+
50
+ return fs . readFileSync ( fullPath , 'utf8' ) ;
51
+ }
52
+
53
+ function getEntrypointData ( config , entryName ) {
54
+ const entrypointsData = JSON . parse ( readOutputFileContents ( 'entrypoints.json' , config ) ) ;
55
+
56
+ if ( typeof entrypointsData . entrypoints [ entryName ] === 'undefined' ) {
57
+ throw new Error ( `The entry ${ entryName } was not found!` ) ;
58
+ }
59
+
60
+ return entrypointsData . entrypoints [ entryName ] ;
61
+ }
62
+
45
63
describe ( 'Functional tests using webpack' , function ( ) {
46
64
// being functional tests, these can take quite long
47
65
this . timeout ( 8000 ) ;
@@ -318,6 +336,22 @@ describe('Functional tests using webpack', function() {
318
336
} ) ;
319
337
} ) ;
320
338
339
+ it ( '.mjs files are supported natively' , ( done ) => {
340
+ const config = createWebpackConfig ( 'web/build' , 'dev' ) ;
341
+ config . addEntry ( 'main' , './js/hello_world' ) ;
342
+ config . setPublicPath ( '/build' ) ;
343
+
344
+ testSetup . runWebpack ( config , ( webpackAssert ) => {
345
+ // check that main.js has the correct contents
346
+ webpackAssert . assertOutputFileContains (
347
+ 'main.js' ,
348
+ 'Hello World!'
349
+ ) ;
350
+
351
+ done ( ) ;
352
+ } ) ;
353
+ } ) ;
354
+
321
355
describe ( 'addStyleEntry .js files are removed' , ( ) => {
322
356
it ( 'Without versioning' , ( done ) => {
323
357
const config = createWebpackConfig ( 'web' , 'dev' ) ;
@@ -1628,7 +1662,7 @@ module.exports = {
1628
1662
} ) ;
1629
1663
} ) ;
1630
1664
1631
- describe ( 'entrypoints.json' , ( ) => {
1665
+ describe ( 'entrypoints.json & splitChunks() ' , ( ) => {
1632
1666
it ( 'Use "all" splitChunks & look at entrypoints.json' , ( done ) => {
1633
1667
const config = createWebpackConfig ( 'web/build' , 'dev' ) ;
1634
1668
config . addEntry ( 'main' , [ './css/roboto_font.css' , './js/no_require' , 'vue' ] ) ;
@@ -1760,18 +1794,18 @@ module.exports = {
1760
1794
webpackAssert . assertOutputJsonFileMatches ( 'entrypoints.json' , {
1761
1795
entrypoints : {
1762
1796
main : {
1763
- js : [ '/build/runtime.js' , '/build/vendors~cc515e6e .js' , '/build/default~cc515e6e .js' , '/build/main.js' ] ,
1764
- css : [ '/build/default~cc515e6e .css' ]
1797
+ js : [ '/build/runtime.js' , '/build/0 .js' , '/build/1 .js' , '/build/main.js' ] ,
1798
+ css : [ '/build/1 .css' ]
1765
1799
} ,
1766
1800
other : {
1767
- js : [ '/build/runtime.js' , '/build/vendors~cc515e6e .js' , '/build/default~cc515e6e .js' , '/build/other.js' ] ,
1768
- css : [ '/build/default~cc515e6e .css' ]
1801
+ js : [ '/build/runtime.js' , '/build/0 .js' , '/build/1 .js' , '/build/other.js' ] ,
1802
+ css : [ '/build/1 .css' ]
1769
1803
}
1770
1804
}
1771
1805
} ) ;
1772
1806
1773
1807
// make split chunks are correct in manifest
1774
- webpackAssert . assertManifestKeyExists ( 'build/vendors~cc515e6e .js' ) ;
1808
+ webpackAssert . assertManifestKeyExists ( 'build/0 .js' ) ;
1775
1809
1776
1810
done ( ) ;
1777
1811
} ) ;
@@ -1809,19 +1843,95 @@ module.exports = {
1809
1843
} ) ;
1810
1844
} ) ;
1811
1845
1812
- it ( '.mjs files are supported natively' , ( done ) => {
1813
- const config = createWebpackConfig ( 'web/build' , 'dev' ) ;
1814
- config . addEntry ( 'main' , './js/hello_world' ) ;
1815
- config . setPublicPath ( '/build' ) ;
1846
+ it ( 'Make sure chunkIds do not change between builds' , ( done ) => {
1847
+ // https://github.com/symfony/webpack-encore/issues/461
1848
+ const createSimilarConfig = function ( includeExtraEntry ) {
1849
+ const config = createWebpackConfig ( 'web/build' , 'production' ) ;
1850
+ config . addEntry ( 'main1' , './js/code_splitting' ) ;
1851
+ if ( includeExtraEntry ) {
1852
+ config . addEntry ( 'main2' , './js/eslint' ) ;
1853
+ }
1854
+ config . addEntry ( 'main3' , './js/no_require' ) ;
1855
+ config . setPublicPath ( '/build' ) ;
1816
1856
1817
- testSetup . runWebpack ( config , ( webpackAssert ) => {
1818
- // check that main.js has the correct contents
1819
- webpackAssert . assertOutputFileContains (
1820
- 'main.js' ,
1821
- 'Hello World!'
1822
- ) ;
1857
+ return config ;
1858
+ } ;
1823
1859
1824
- done ( ) ;
1860
+ const configA = createSimilarConfig ( false ) ;
1861
+ const configB = createSimilarConfig ( true ) ;
1862
+
1863
+ testSetup . runWebpack ( configA , ( ) => {
1864
+ testSetup . runWebpack ( configB , ( ) => {
1865
+ const main3Contents = readOutputFileContents ( 'main3.js' , configA ) ;
1866
+ const finalMain3Contents = readOutputFileContents ( 'main3.js' , configB ) ;
1867
+
1868
+ if ( finalMain3Contents !== main3Contents ) {
1869
+ throw new Error ( `Contents after first compile do not match after second compile: \n\n ${ main3Contents } \n\n versus \n\n ${ finalMain3Contents } \n` ) ;
1870
+ }
1871
+
1872
+ done ( ) ;
1873
+ } ) ;
1874
+ } ) ;
1875
+ } ) ;
1876
+
1877
+ it ( 'Do not change contents or filenames when more modules require the same split contents' , ( done ) => {
1878
+ const createSimilarConfig = function ( includeExtraEntry ) {
1879
+ const config = createWebpackConfig ( 'web/build' , 'production' ) ;
1880
+ config . addEntry ( 'main1' , [ './js/code_splitting' , 'preact' ] ) ;
1881
+ config . addEntry ( 'main3' , [ './js/no_require' , 'preact' ] ) ;
1882
+ if ( includeExtraEntry ) {
1883
+ config . addEntry ( 'main4' , [ './js/eslint' , 'preact' ] ) ;
1884
+ }
1885
+ config . setPublicPath ( '/build' ) ;
1886
+ config . splitEntryChunks ( ) ;
1887
+ config . configureSplitChunks ( ( splitChunks ) => {
1888
+ // will include preact, but prevent any other splitting
1889
+ splitChunks . minSize = 10000 ;
1890
+ } ) ;
1891
+
1892
+ return config ;
1893
+ } ;
1894
+
1895
+ const getSplitVendorJsPath = function ( config ) {
1896
+ const entrypointData = getEntrypointData ( config , 'main3' ) ;
1897
+
1898
+ const splitFiles = entrypointData . js . filter ( filename => {
1899
+ return filename !== '/build/runtime.js' && filename !== '/build/main3.js' ;
1900
+ } ) ;
1901
+
1902
+ // sanity check
1903
+ if ( splitFiles . length !== 1 ) {
1904
+ throw new Error ( `Unexpected number (${ splitFiles . length } ) of split files for main3 entry` ) ;
1905
+ }
1906
+
1907
+ return splitFiles [ 0 ] ;
1908
+ } ;
1909
+
1910
+ const configA = createSimilarConfig ( false ) ;
1911
+ const configB = createSimilarConfig ( true ) ;
1912
+
1913
+ testSetup . runWebpack ( configA , ( ) => {
1914
+ testSetup . runWebpack ( configB , ( ) => {
1915
+ const vendorPath = getSplitVendorJsPath ( configA ) ;
1916
+ const finalVendorPath = getSplitVendorJsPath ( configB ) ;
1917
+
1918
+ // make sure that the filename of the split vendor file didn't change,
1919
+ // even though an additional entry is now sharing its contents
1920
+ if ( finalVendorPath !== vendorPath ) {
1921
+ throw new Error ( `Vendor filename changed! Before ${ vendorPath } and after ${ finalVendorPath } .` ) ;
1922
+ }
1923
+
1924
+ // make sure that, internally, the split chunk name did not change,
1925
+ // which would cause the contents of main3 to suddenly change
1926
+ const main3Contents = readOutputFileContents ( 'main3.js' , configA ) ;
1927
+ const finalMain3Contents = readOutputFileContents ( 'main3.js' , configB ) ;
1928
+
1929
+ if ( finalMain3Contents !== main3Contents ) {
1930
+ throw new Error ( `Contents after first compile do not match after second compile: \n\n ${ main3Contents } \n\n versus \n\n ${ finalMain3Contents } \n` ) ;
1931
+ }
1932
+
1933
+ done ( ) ;
1934
+ } ) ;
1825
1935
} ) ;
1826
1936
} ) ;
1827
1937
} ) ;
0 commit comments