I'm trying to use the new top level await that was added in Node v14.8. See here and here for more info. I've not found a question on here about issues with using this new feature, but I hope this isn't a duplicate. The closest is @DanStarns answer on this question, but I have tried his solution as well (and his answer was before the 14.8 release).
I'm in the process of extracting my Axios instance from my controller into a standalone service. In that service file, I'm attempting to instantiate and then export an Axios instance created with a stored authorization header from Spotify's API. Since this is then imported into my controller (passed into the constructor then it exports new SpotifyApiController(SpotifyApiService)) and imports are synchronous, I am trying to use the new top level await feature to have this fully instantiated at startup/import, but getting the following error:
[nodemon] starting `babel-node bin/www.js --harmony-top-level-await --experimental-repl-await`
E:\projects\harmonic-mixing-companion\server\services\SpotifyApiService.mjs:117
var SpotifyApiService = await createApiService();
^^^^^
SyntaxError: await is only valid in async function
at wrapSafe (internal/modules/cjs/loader.js:979:16)
at Module._compile (internal/modules/cjs/loader.js:1027:27)
at Module._compile (E:\projects\harmonic-mixing-companion\server\node_modules\pirates\lib\index.js:99:24)
at Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Object.newLoader [as .mjs] (E:\projects\harmonic-mixing-companion\server\node_modules\pirates\lib\index.js:104:7)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
at Module.require (internal/modules/cjs/loader.js:952:19)
at require (internal/modules/cjs/helpers.js:88:18)
at Object.<anonymous> (E:\projects\harmonic-mixing-companion\server\controllers\/SpotifyApiController.js:1:1)
From the error, it looks like babel-node is transpiling my code properly since const SpotifyApiService = ... became var SpotifyApiService = .... I have also added "@babel/plugin-syntax-top-level-await" to my babel.config.json.
The service's file extension is .mjs. I have also tried setting "type": "module" in my server's package.json too, but that was unfruitful as well. Correct me if I'm wrong, but it also doesn't sound right to me for my whole backend server to be set as a module because it doesn't sound like a modular unit to me (versus a reusable SpotifyApiService).
Double checked my node's version using console.log(process.version); at the top of my main entry file and it printed the expected 14.14.0 version.
SpotifyApiController.js Snippet:
import SpotifyApiService from '../services/SpotifyApiService.mjs';
import handleHttpError from '../handlers/handleHttpError';
class SpotifyApiController {
constructor(spotifyApiService) {
this.spotifyApi = spotifyApiService;
}
...
}
SpotifyApiService.mjs Snippet:
...
const createApiService = async () => {
const accessToken = await authorizeApp();
console.log(accessToken);
const authHeader = { Authorization: `Bearer ${accessToken}` };
const axiosInstance = axios.create({
baseURL: 'https://api.spotify.com/v1',
headers: authHeader,
});
createAuthRefreshInterceptor(axiosInstance, authorizeApp);
return axiosInstance;
};
const SpotifyApiService = await createApiService();
export default SpotifyApiService;
package.json Dependencies:
"devDependencies": {
"@babel/cli": "~7.12.1",
"@babel/core": "~7.12.1",
"@babel/eslint-parser": "~7.12.1",
"@babel/node": "~7.12.1",
"@babel/plugin-proposal-class-properties": "~7.12.1",
"@babel/plugin-syntax-top-level-await": "~7.12.1",
"@babel/plugin-transform-arrow-functions": "~7.12.1",
"@babel/plugin-transform-runtime": "~7.12.1",
"@babel/preset-env": "~7.12.1",
"@babel/preset-react": "~7.12.1",
"babel-loader": "~8.1.0",
"nodemon": "~2.0.5"
},
"dependencies": {
"axios": "~0.20.0",
"axios-auth-refresh": "~3.0.0",
"cookie-parser": "~1.4.5",
"cors": "~2.8.5",
"debug": "~4.2.0",
"dotenv": "~8.2.0",
"express": "~4.17.1",
"querystring": "~0.2.0"
}
Server is started with the following npm script: "dev-server": "nodemon --exec babel-node bin/www.js --ignore dist/"
You can wrap it in async function:
var SpotifyApiService = (async()=> await createApiService())();
After you can use than, catch
As the documentation indicates, babel only enables the "syntax" for this feature,
Syntax only
This plugin only enables parsing of this feature. Babel doesn't support transforming top-level await, but you can use Rollup's experimentalTopLevelAwait or webpack@5's experiments.topLevelAwait options.
which just means that babel won't complain when compiling your code but it doesn't actually implement the steps that will actively transform a line such as var SpotifyApiService = await createApiService(); into valid ES5.
So anything executing your code ( browser, node ) will complain since they don't know how to handle this feature.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With