From 2952e4aaa0ecf07f6cd1b8f0652a93d4eca4535c Mon Sep 17 00:00:00 2001 From: Ryan Tsao Date: Tue, 28 Aug 2018 09:42:04 -0700 Subject: [PATCH] Fix assetUrl for non-browser compilations, simplify implementation --- .../babel-plugin-asseturl/index.js | 6 +- .../fixtures/expected-import-destructuring | 4 +- .../fixtures/expected-import-destructuring-as | 2 +- build/compiler.js | 11 +- build/file-loader-asset-manifest-plugin.js | 45 -------- build/file-loader-asset-storage.js | 29 ----- build/file-loader.js | 102 +++--------------- test/cli/build.js | 18 ++++ test/cli/dev.js | 9 ++ test/fixtures/assets/.fusionrc.js | 3 + test/fixtures/assets/src/main.js | 4 + test/fixtures/assets/src/server-asset.js | 0 .../assets/src/static/test-server-asset.txt | 1 + test/fixtures/compress-assets/src/main.js | 1 - test/fixtures/server-assets/.fusionrc.js | 3 + .../server-assets/src/assets/server-asset.txt | 1 + .../src/assets/universal-asset.txt | 1 + test/fixtures/server-assets/src/main.js | 14 +++ .../server-assets/src/server-assets.js | 3 + 19 files changed, 82 insertions(+), 175 deletions(-) delete mode 100644 build/file-loader-asset-manifest-plugin.js delete mode 100644 build/file-loader-asset-storage.js create mode 100644 test/fixtures/assets/.fusionrc.js create mode 100644 test/fixtures/assets/src/server-asset.js create mode 100644 test/fixtures/assets/src/static/test-server-asset.txt create mode 100644 test/fixtures/server-assets/.fusionrc.js create mode 100644 test/fixtures/server-assets/src/assets/server-asset.txt create mode 100644 test/fixtures/server-assets/src/assets/universal-asset.txt create mode 100644 test/fixtures/server-assets/src/main.js create mode 100644 test/fixtures/server-assets/src/server-assets.js diff --git a/build/babel-plugins/babel-plugin-asseturl/index.js b/build/babel-plugins/babel-plugin-asseturl/index.js index cad94245..6dfe1d70 100644 --- a/build/babel-plugins/babel-plugin-asseturl/index.js +++ b/build/babel-plugins/babel-plugin-asseturl/index.js @@ -42,11 +42,7 @@ function refsHandler(t, context, refs = []) { } args[0].replaceWith( t.callExpression(t.identifier('require'), [ - t.stringLiteral( - `__SECRET_FILE_LOADER__?storeFile=true&storeFileTarget=node!${ - args[0].node.value - }` - ), + t.stringLiteral(`__SECRET_FILE_LOADER__!${args[0].node.value}`), ]) ); }); diff --git a/build/babel-plugins/babel-plugin-asseturl/test/fixtures/expected-import-destructuring b/build/babel-plugins/babel-plugin-asseturl/test/fixtures/expected-import-destructuring index 6fc71db0..c5320920 100644 --- a/build/babel-plugins/babel-plugin-asseturl/test/fixtures/expected-import-destructuring +++ b/build/babel-plugins/babel-plugin-asseturl/test/fixtures/expected-import-destructuring @@ -1,6 +1,6 @@ import { assetUrl } from 'fusion-core'; import { assetUrl as assetUrlOther } from 'assetUrl'; const path = './test'; -assetUrl(require("__SECRET_FILE_LOADER__?storeFile=true&storeFileTarget=node!./path")); +assetUrl(require("__SECRET_FILE_LOADER__!./path")); assetUrlOther(path); -assetUrl(require("__SECRET_FILE_LOADER__?storeFile=true&storeFileTarget=node!./path")); \ No newline at end of file +assetUrl(require("__SECRET_FILE_LOADER__!./path")); diff --git a/build/babel-plugins/babel-plugin-asseturl/test/fixtures/expected-import-destructuring-as b/build/babel-plugins/babel-plugin-asseturl/test/fixtures/expected-import-destructuring-as index 8ccbd754..eda83e68 100644 --- a/build/babel-plugins/babel-plugin-asseturl/test/fixtures/expected-import-destructuring-as +++ b/build/babel-plugins/babel-plugin-asseturl/test/fixtures/expected-import-destructuring-as @@ -1,4 +1,4 @@ import { assetUrl as frameworkAssetUrl } from 'fusion-core'; import assetUrl from 'assetURL'; assetUrl('./path'); -frameworkAssetUrl(require("__SECRET_FILE_LOADER__?storeFile=true&storeFileTarget=node!./path")); \ No newline at end of file +frameworkAssetUrl(require("__SECRET_FILE_LOADER__!./path")); diff --git a/build/compiler.js b/build/compiler.js index 5cb4815a..4509884c 100644 --- a/build/compiler.js +++ b/build/compiler.js @@ -25,7 +25,7 @@ const { } = require('../lib/compression'); const resolveFrom = require('resolve-from'); -const AssetsManifestPlugin = require('./file-loader-asset-manifest-plugin'); +// const AssetsManifestPlugin = require('./file-loader-asset-manifest-plugin'); const ClientSourceMapPlugin = require('./client-source-map-plugin'); const ChunkModuleManifestPlugin = require('./chunk-module-manifest-plugin'); const chunkModuleManifest = require('./chunk-module-manifest'); @@ -411,14 +411,12 @@ function getConfig({target, env, dir, watch, cover}) { }, plugins: [ new ProgressBarPlugin(), - // TODO(#9): relying only on timestamp will invalidate service worker after every build - // optimize by importing all chunk names to sw and then remove timestamp in non-dev. - target === 'web' && env === 'production' && zopfliWebpackPlugin, // gzip + env === 'production' && zopfliWebpackPlugin, // gzip // generate compressed files - target === 'web' && env === 'production' && brotliWebpackPlugin, // brotli + env === 'production' && brotliWebpackPlugin, // brotli // target === 'web' && env === 'production' && pngquantWebpackPlugin, // png TODO(#10): production server requires libpng-dev installed to use this // target === 'web' && env === 'production' && guetzliWebpackPlugin, // jpg TODO(#10): guetzli also depends on libpng-dev for some reason - target === 'web' && env === 'production' && svgoWebpackPlugin, // svg + env === 'production' && svgoWebpackPlugin, // svg // In development, skip the emitting phase on errors to ensure there are // no assets emitted that include errors. This fixes an issue with hot reloading // server side code and recovering from errors correctly. We only want to do this @@ -474,7 +472,6 @@ function getConfig({target, env, dir, watch, cover}) { }), // case-insensitive paths can cause problems new CaseSensitivePathsPlugin(), - target === 'web' && new AssetsManifestPlugin(), target === 'node' && new webpack.BannerPlugin({ raw: true, diff --git a/build/file-loader-asset-manifest-plugin.js b/build/file-loader-asset-manifest-plugin.js deleted file mode 100644 index 1cd2870a..00000000 --- a/build/file-loader-asset-manifest-plugin.js +++ /dev/null @@ -1,45 +0,0 @@ -// @flow -/* eslint-env node */ -const assetsSingleton = require('./file-loader-asset-storage.js'); - -class AssetsManifestPlugin { - // eslint-disable-next-line class-methods-use-this - apply(compiler /*: any */) { - const onCompilation = compilation => { - const additionalAssetsHook = cb => { - const storage = assetsSingleton.getStorage(); - storage.emittedFiles.forEach(item => { - // eslint-disable-next-line no-param-reassign - compilation.assets[item.outputPath] = { - source: () => item.content, - size: () => Buffer.byteLength(item.content, 'utf8'), - }; - }); - cb(); - }; - - if (compilation.hooks) { - compilation.hooks.additionalAssets.tapAsync( - 'AssetsManifestPlugin', - additionalAssetsHook - ); - } else { - compilation.plugin('additional-assets', additionalAssetsHook); - } - }; - - const onEmit = (compilation, cb) => { - cb(); - }; - - if (compiler.hooks) { - compiler.hooks.emit.tapAsync('AssetsManifestPlugin', onEmit); - compiler.hooks.compilation.tap('AssetsManifestPlugin', onCompilation); - } else { - compiler.plugin('compilation', onCompilation); - compiler.plugin('emit', onEmit); - } - } -} - -module.exports = AssetsManifestPlugin; diff --git a/build/file-loader-asset-storage.js b/build/file-loader-asset-storage.js deleted file mode 100644 index 004322f4..00000000 --- a/build/file-loader-asset-storage.js +++ /dev/null @@ -1,29 +0,0 @@ -/* eslint-env node */ - -// @flow -const FileLoaderStorage = (function getLoaderStorage() { - let instance = null; - - function createFileLoaderStorage() { - const emittedFiles = []; - - function addFileItem(outputPath /*: string */, content /*: string */) { - emittedFiles.push({outputPath, content}); - } - return { - emittedFiles, - addFile: addFileItem, - }; - } - - return { - getStorage: function getStorage() { - if (!instance) { - instance = createFileLoaderStorage(); - } - return instance; - }, - }; -})(); - -module.exports = FileLoaderStorage; diff --git a/build/file-loader.js b/build/file-loader.js index a4bbaf9b..b7591e2d 100644 --- a/build/file-loader.js +++ b/build/file-loader.js @@ -1,93 +1,25 @@ +/** Copyright (c) 2018 Uber Technologies, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ /* eslint-env node */ -// @flow -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ -const path = require('path'); -const loaderUtils = require('loader-utils'); -const storageSingleton = require('./file-loader-asset-storage.js'); -module.exports = function fileLoader(content /*: string */) { - if (!this.emitFile) - throw new Error('emitFile is required from module system'); - - const options = loaderUtils.getOptions(this) || {}; - - const config = { - publicPath: undefined, - useRelativePath: false, - name: '[hash].[ext]', - storeFile: false, - storeFileTarget: null, - }; - - // options takes precedence over config - Object.keys(options).forEach(attr => { - config[attr] = options[attr]; - }); +const path = require("path"); +const loaderUtils = require("loader-utils"); - const context = - options.context || - this.rootContext || - (this.options && this.options.context); - let url = loaderUtils.interpolateName(this, config.name, { - context, - content, - regExp: void 0, +module.exports = function fileLoader(content /*: string */) { + const url = loaderUtils.interpolateName(this, "[hash].[ext]", { + context: this.rootContext, + content }); - let outputPath = ''; - - const filePath = this.resourcePath; - if (config.useRelativePath) { - // eslint-disable-next-line no-mixed-operators - const issuerContext = - (this._module && this._module.issuer && this._module.issuer.context) || - context; - const relativeUrl = - issuerContext && - path - .relative(issuerContext, filePath) - .split(path.sep) - .join('/'); - const relativePath = relativeUrl && `${path.dirname(relativeUrl)}/`; - // eslint-disable-next-line no-bitwise - if (~relativePath.indexOf('../')) { - // eslint-disable-line no-bitwise - outputPath = path.posix.join(outputPath, relativePath, url); - } else { - outputPath = relativePath + url; - } - url = relativePath + url; - } else { - outputPath = url; - } + // Assets should always go into client dist directory, regardless of source + const outputPath = path.posix.join("../client", url); - let publicPath = `__webpack_public_path__ + ${JSON.stringify(url)}`; - if (config.publicPath !== undefined) { - // support functions as publicPath to generate them dynamically - publicPath = JSON.stringify( - typeof config.publicPath === 'function' - ? config.publicPath(url) - : config.publicPath + url - ); - } + this.emitFile(outputPath, content); - const storage = storageSingleton.getStorage(); - const {storeFile, storeFileTarget} = config; - if (options.emitFile === undefined || options.emitFile) { - // when storeFile param is passed we don't emit a file - // but store it to be added added later as an additional asset to a compilation - // it allows adding these files in a different compilation - if (storeFile && (!storeFileTarget || this.target === storeFileTarget)) { - storage.addFile(outputPath, content); - } else { - this.emitFile(outputPath, content); - } - } - - return `module.exports = ${publicPath};`; + return `module.exports = __webpack_public_path__ + ${JSON.stringify(url)};`; }; - -module.exports.raw = true; diff --git a/test/cli/build.js b/test/cli/build.js index ebcd8796..393a99df 100644 --- a/test/cli/build.js +++ b/test/cli/build.js @@ -455,6 +455,24 @@ test('`fusion build` compresses assets for production', async t => { t.end(); }); +test('`fusion build` puts server assets in client directory', async t => { + const dir = path.resolve(__dirname, '../fixtures/server-assets'); + await cmd(`build --dir=${dir} --production`); + + const fusion_folder = '.fusion/dist/production/client/'; + fs.readdir(path.resolve(dir, fusion_folder), (err, files) => { + t.ok( + files.includes('54dcbe888c1b1145462ae09d6610ab82.txt'), + 'has server asset' + ); + t.ok( + files.includes('2642b2c23331388417654062a7058f82.txt'), + 'has universal asset' + ); + }); + t.end(); +}); + test('`fusion build` with dynamic imports', async t => { const dir = path.resolve(__dirname, '../fixtures/dynamic-import'); await cmd(`build --dir=${dir}`); diff --git a/test/cli/dev.js b/test/cli/dev.js index 2d53e04f..d61cd361 100644 --- a/test/cli/dev.js +++ b/test/cli/dev.js @@ -60,6 +60,15 @@ test('`fusion dev` works with assets', async t => { fs.readFileSync(path.resolve(dir, 'src/static/test.css')).toString(), 'serves css file from memory correctly' ); + t.equal( + await request( + `http://localhost:${port}/_static/b78cb0eaf8604dad0108350cb5149457.txt` + ), + fs + .readFileSync(path.resolve(dir, 'src/static/test-server-asset.txt')) + .toString(), + 'serves server asset from memory correctly' + ); t.equal(await request(`http://localhost:${port}/dirname`), 'src'); t.equal(await request(`http://localhost:${port}/filename`), 'src/main.js'); t.equal( diff --git a/test/fixtures/assets/.fusionrc.js b/test/fixtures/assets/.fusionrc.js new file mode 100644 index 00000000..dabf00db --- /dev/null +++ b/test/fixtures/assets/.fusionrc.js @@ -0,0 +1,3 @@ +module.exports = { + assumeNoImportSideEffects: true +}; diff --git a/test/fixtures/assets/src/main.js b/test/fixtures/assets/src/main.js index 8a243275..7e739e33 100644 --- a/test/fixtures/assets/src/main.js +++ b/test/fixtures/assets/src/main.js @@ -8,6 +8,8 @@ if (typeof window !== 'undefined') { window.__hoistedUrl__ = hoistedUrl; } +import {serverAsset} from "./server-asset.js"; + export default (async function() { const app = new App('element', el => el); __NODE__ && @@ -26,6 +28,8 @@ export default (async function() { ctx.body = assetUrl('./static/test.json'); } else if (ctx.url === '/json-import') { ctx.body = JSON.stringify(jsonData); + } else if (ctx.url === '/server-asset') { + ctx.body = assetUrl("./static/test-server-asset.txt"); } return next(); }); diff --git a/test/fixtures/assets/src/server-asset.js b/test/fixtures/assets/src/server-asset.js new file mode 100644 index 00000000..e69de29b diff --git a/test/fixtures/assets/src/static/test-server-asset.txt b/test/fixtures/assets/src/static/test-server-asset.txt new file mode 100644 index 00000000..de84a8f2 --- /dev/null +++ b/test/fixtures/assets/src/static/test-server-asset.txt @@ -0,0 +1 @@ +test server assets diff --git a/test/fixtures/compress-assets/src/main.js b/test/fixtures/compress-assets/src/main.js index 76ba6d1c..a6f7fb63 100644 --- a/test/fixtures/compress-assets/src/main.js +++ b/test/fixtures/compress-assets/src/main.js @@ -1,7 +1,6 @@ import App from 'fusion-core'; import {assetUrl} from 'fusion-core'; - export default async function() { const app = new App('element', el => el); assetUrl('./assets/SVG_logo.svg'); diff --git a/test/fixtures/server-assets/.fusionrc.js b/test/fixtures/server-assets/.fusionrc.js new file mode 100644 index 00000000..dabf00db --- /dev/null +++ b/test/fixtures/server-assets/.fusionrc.js @@ -0,0 +1,3 @@ +module.exports = { + assumeNoImportSideEffects: true +}; diff --git a/test/fixtures/server-assets/src/assets/server-asset.txt b/test/fixtures/server-assets/src/assets/server-asset.txt new file mode 100644 index 00000000..99c0ae25 --- /dev/null +++ b/test/fixtures/server-assets/src/assets/server-asset.txt @@ -0,0 +1 @@ +server asset diff --git a/test/fixtures/server-assets/src/assets/universal-asset.txt b/test/fixtures/server-assets/src/assets/universal-asset.txt new file mode 100644 index 00000000..af560580 --- /dev/null +++ b/test/fixtures/server-assets/src/assets/universal-asset.txt @@ -0,0 +1 @@ +universal asset diff --git a/test/fixtures/server-assets/src/main.js b/test/fixtures/server-assets/src/main.js new file mode 100644 index 00000000..67c9836e --- /dev/null +++ b/test/fixtures/server-assets/src/main.js @@ -0,0 +1,14 @@ +import App, {assetUrl} from 'fusion-core'; + +import {serverAsset} from "./server-assets.js"; + +const asset = assetUrl('./assets/universal-asset.txt'); + +export default async function() { + const app = new App('element', el => el); + if (__NODE__) { + serverAsset(); + } + console.log(asset); + return app; +} diff --git a/test/fixtures/server-assets/src/server-assets.js b/test/fixtures/server-assets/src/server-assets.js new file mode 100644 index 00000000..ebadca12 --- /dev/null +++ b/test/fixtures/server-assets/src/server-assets.js @@ -0,0 +1,3 @@ +import {assetUrl} from 'fusion-core'; + +export const serverAsset = () => assetUrl('./assets/server-asset.txt');