Skip to content

Commit 7bec574

Browse files
committed
bug #536 Fix JSON files support in Encore.copyFiles() (Lyrkan)
This PR was merged into the master branch. Discussion ---------- Fix JSON files support in Encore.copyFiles() This PR fixes #535. As explained in the issue, the current version doesn't allow `Encore.copyFiles()` to process JSON files because of how Webpack 4 handles them. Basically, from what I understand, for most of the files it works that way: ``` Imported file (module.type = javascript/auto) => file-loader (takes anything, returns JS content) => Webpack JS parser ``` But for `.json` files the JS parser is replaced by a JSON parser: ``` Imported file (module.type = json) => file-loader (takes anything, returns JS content) => Webpack JSON parser ``` Since that "Webpack JSON parser" part expects JSON data (and not something that contains JS), the compilation fails at that point. There is no way to disable that behavior when you specify loaders the "inline" way... which is what we do for `Encore.copyFiles()`, you can only do it by defining a config rule that forces the `javascript/auto` type. What the PR does: it adds another loader in front of the file-loader that returns the input it received but after setting its `_module.type` (and the generator/parser that go with it) to `javascript/auto`. So in the end we get: ``` Imported file (module.type = json) => file-loader (takes anything, returns JS content) => copy-files-loader (sets type to javascript/auto and returns the same content) => Webpack JS parser ``` Commits ------- 4ef8c2a Fix JSON files support in Encore.copyFiles()
2 parents 112ec4b + 4ef8c2a commit 7bec574

File tree

6 files changed

+87
-1
lines changed

6 files changed

+87
-1
lines changed

fixtures/copy/foo.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This is an invalid content to check that the file is still copied

fixtures/copy/foo.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This is an invalid content to check that the file is still copied

fixtures/copy/foo.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This is an invalid content to check that the file is still copied

lib/config-generator.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,10 @@ class ConfigGenerator {
183183
copyTo = this.webpackConfig.useVersioning ? '[path][name].[hash:8].[ext]' : '[path][name].[ext]';
184184
}
185185

186+
const copyFilesLoader = require.resolve('./webpack/copy-files-loader');
187+
const fileLoader = require.resolve('file-loader');
186188
const copyContext = entry.context ? path.resolve(this.webpackConfig.getContext(), entry.context) : copyFrom;
187-
const requireContextParam = `!${require.resolve('file-loader')}?context=${copyContext}&name=${copyTo}!${copyFrom}`;
189+
const requireContextParam = `!${copyFilesLoader}!${fileLoader}?context=${copyContext}&name=${copyTo}!${copyFrom}`;
188190

189191
return buffer + `
190192
const context_${index} = require.context(

lib/webpack/copy-files-loader.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* This file is part of the Symfony Webpack Encore package.
3+
*
4+
* (c) Fabien Potencier <[email protected]>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
'use strict';
11+
12+
const LoaderDependency = require('webpack/lib/dependencies/LoaderDependency');
13+
14+
module.exports = function loader(source) {
15+
// This is a hack that allows `Encore.copyFiles()` to support
16+
// JSON files using the file-loader (which is not something
17+
// that is supported in Webpack 4, see https://github.com/symfony/webpack-encore/issues/535)
18+
//
19+
// Since there is no way to change the module's resource type from a loader
20+
// without using private properties yet we have to use "this._module".
21+
//
22+
// By setting its type to 'javascript/auto' Webpack won't try parsing
23+
// the result of the loader as a JSON object.
24+
//
25+
// For more information:
26+
// https://github.com/webpack/webpack/issues/6572#issuecomment-368376326
27+
// https://github.com/webpack/webpack/issues/7057
28+
const requiredType = 'javascript/auto';
29+
if (this._module.type !== requiredType) {
30+
// Try to retrieve the factory used by the LoaderDependency type
31+
// which should be the NormalModuleFactory.
32+
const factory = this._compilation.dependencyFactories.get(LoaderDependency);
33+
if (factory === undefined) {
34+
throw new Error('Could not retrieve module factory for type LoaderDependency');
35+
}
36+
37+
this._module.type = requiredType;
38+
this._module.generator = factory.getGenerator(requiredType);
39+
this._module.parser = factory.getParser(requiredType);
40+
}
41+
42+
return source;
43+
};

test/functional.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,6 +1891,44 @@ module.exports = {
18911891
done();
18921892
});
18931893
});
1894+
1895+
it('Copy files without processing them', (done) => {
1896+
const config = createWebpackConfig('www/build', 'production');
1897+
config.addEntry('main', './js/no_require');
1898+
config.setPublicPath('/build');
1899+
config.copyFiles({ from: './copy' });
1900+
1901+
// By default the optimize-css-assets-webpack-plugin will
1902+
// run on ALL emitted CSS files, which includes the ones
1903+
// handled by `Encore.copyFiles()`.
1904+
// We disable it for this test since our CSS file will
1905+
// not be valid and can't be handled by this plugin.
1906+
config.configureOptimizeCssPlugin(options => {
1907+
options.assetNameRegExp = /^$/;
1908+
});
1909+
1910+
testSetup.runWebpack(config, (webpackAssert) => {
1911+
expect(config.outputPath).to.be.a.directory()
1912+
.with.files([
1913+
'entrypoints.json',
1914+
'runtime.js',
1915+
'main.js',
1916+
'manifest.json',
1917+
'foo.css',
1918+
'foo.js',
1919+
'foo.json',
1920+
]);
1921+
1922+
for (const file of ['foo.css', 'foo.js', 'foo.json']) {
1923+
webpackAssert.assertOutputFileContains(
1924+
file,
1925+
'This is an invalid content to check that the file is still copied'
1926+
);
1927+
}
1928+
1929+
done();
1930+
});
1931+
});
18941932
});
18951933

18961934
describe('entrypoints.json & splitChunks()', () => {

0 commit comments

Comments
 (0)