Cannot deploy nest.js project to Google Firebase Functions - javascript

NestJs uses ES6, ES7 and ES8, but Firebase Functions is stuck at Node v.6.11.
I tried to write a webpack config file w/ babel to transpile both my files and the node_modules to node v6.11 but I'm not able to complete the deploy due to a syntax error caused by an async function in the #nestjs/common/interceptors/file-fields.interceptor.js file.
⚠ functions[api]: Deployment error.
Function load error: Code in file dist/index.js can't be loaded.
Is there a syntax error in your code?
Detailed stack trace: /user_code/node_modules/#nestjs/common/interceptors/file-fields.interceptor.js:10
async intercept(context, call$) {
^^^^^^^^^
SyntaxError: Unexpected identifier
at createScript (vm.js:56:10)
at Object.runInThisContext (vm.js:97:10)
at Module._compile (module.js:549:28)
at Object.Module._extensions..js (module.js:586:10)
at Module.load (module.js:494:32)
at tryModuleLoad (module.js:453:12)
at Function.Module._load (module.js:445:3)
at Module.require (module.js:504:17)
at require (internal/module.js:20:19)
at Object.<anonymous> (/user_code/node_modules/#nestjs/common/interceptors/index.js:6:10)
Here's my webpack.config.js file:
'use strict';
const nodeExternals = require('webpack-node-externals');
module.exports = {
entry: './src/server.ts',
output: {
filename: 'index.js',
libraryTarget: 'this'
},
target: 'node',
module: {
rules: [
{
test: /\.tsx?$/,
use: [
{
loader: 'babel-loader',
options: {
presets: [
[
'#babel/preset-env',
{
"targets": {
"node": "6.11.1"
}
},
'#babel/stage-0'
]
],
plugins: [require('#babel/plugin-transform-async-to-generator')]
}
},
{
loader: 'ts-loader',
options: {
transpileOnly: true
}
}
]
},
{
test: /\.js$/,
use: [
{
loader: 'babel-loader',
options: {
presets: [
[
'#babel/preset-env',
{
"targets": {
"node": "6.11.1"
}
},
'#babel/stage-0'
]
],
plugins: [require('#babel/plugin-transform-async-to-generator')]
}
}
]
}
]
},
resolve: {
extensions: [ '.ts', '.tsx', '.js' ]
},
externals: [nodeExternals()]
};
My tsconfig.json:
{
"compilerOptions": {
"lib": ["es6", "es2015.promise"],
"module": "commonjs",
"noImplicitAny": false,
"outDir": "",
"sourceMap": true,
"removeComments": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowJs": true,
"target": "es6",
"typeRoots": [
"node_modules/#types"
]
},
"include": [
"src/**/*.ts",
"spec/**/*.ts"
],
"exclude": [
"**/*.spec.ts"
]
}
What's wrong?

Exactly 3 days ago (after Google Cloud’s Next conf) Google just announced the new Node 8 runtime and Firebase Cloud Functions 2.0.0 and Firebase tools to 4.0.0.
Here’s what you need to do to get on the Node 8 train:
Upgrade your firebase-functions version to 2.0.0
Upgrade firebase-tools to 4.0.0
Add "engines": { “node": “8” } to your /functions/package.json
More deets here: https://firebase.google.com/docs/functions/manage-functions#set_nodejs_version

Node 6 won't run any code using the async keyword as it doesn't support async functions from ES2017.
I'd recommend trying to use TypeScript for the transpilation of your code, using es6 as a target in your tsconfig.json. It should transpile async functions. Please keep in mind that you might have to load specific polyfills depending on your needs. And you're probably aware of this detail but NestJS specifies Node 8.9+, as documented here:
We follow the Node.js release schedule which recently moved to 8.x as an active LTS version. Therefore, Nest 5 supports >= 8.9.0 as the lowest version now. This shift gaves us sustainable performance boosts thanks to the es2017 target of the TypeScript compilation.

Related

error Unable to resolve path to module 'html-webpack-plugin' import/no-unresolved

I am getting this error
/home/runner/work/toDoList/toDoList/webpack.config.js
2:35 error Unable to resolve path to module 'html-webpack-plugin' import/no-unresolved
on my linters run by GitHub actions.
I do not get this error when I run eslint locally; this only happens in GitHub actions. These solutions did not work for me.
How to manually add a path to be resolved in eslintrc
Using eslint with typescript - Unable to resolve path to module
eslint / typescript: Unable to resolve path to module
Why I got error Unable to resolve path to module? Eslint with Typescript
https://www.appsloveworld.com/reactjs/200/340/sublime-eslint-plugin-unable-to-resolve-path-to-module-while-the-path-exist
Here is my webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
devtool: 'inline-source-map',
devServer: {
static: './dist',
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
}),
],
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
],
},
};
And my .eslintrc.json
{
"env": {
"browser": true,
"es6": true,
"jest": true
},
"parser": "babel-eslint",
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
},
"extends": ["airbnb-base"],
"rules": {
"no-shadow": "off",
"no-param-reassign": "off",
"eol-last": "off",
"import/extensions": [ 1, {
"js": "always", "json": "always"
}]
},
"ignorePatterns": [
"dist/",
"build/"
]
}
Here is the pull request with error if I'm missing something.
Turns out my html-webpack-plugin wasn't getting installed in the GitHub actions environment because it wasn't in linters.yml file. Adding npm install html-webpack-plugin in linters.yml solved the issue.
#shasherazi is right, in my case I added it like below under eslint
run: | npm install html-webpack-plugin
just before the eslint install command in linters.yml file

How to enable a SharedRuntime Environment in a custom function excel add-in with a separate vuejs taskpane

What I need to do:
Create a shared runtime environment so that my excel custom functions can have access to the workbook information.
Current Setup:
The way the project seems to have been set up is, using the yeoman office generator to generate a custom function addin and then using vue-cli to generate a vue app to use as the taskpane.
Folder Structure:
RootFolder
Add-In
dist
node_modules
src
config.json
manifest.xml
jest.config.js
package.json
tsconfig.json
webpack.config.js
Taskpane
dist
public
node_modules
src
assets
modules
plugins
router
store
views
App.vue
main.ts
shims-vue.d.ts
shims.tsx.d.ts
shims.vuetify.d.ts
.browserlistrc
.eslintrc.js
babel.config.js
package.json
tsconfig.json
vue.config.js
Webpack config for addin prior to changes:
module.exports = async (env, options) => {
const dev = options.mode === "development";
const buildType = dev ? "dev" : "prod";
const config = {
node: {
fs: 'empty' // https://github.com/webpack-contrib/css-loader/issues/447
},
devtool: "source-map",
entry: {
functions: "./src/functions/functions.ts",
polyfill: "#babel/polyfill",
commands: "./src/commands/commands.ts"
},
resolve: {
extensions: [".ts", ".tsx", ".html", ".js"]
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: "babel-loader"
},
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: "ts-loader"
},
{
test: /\.html$/,
exclude: /node_modules/,
use: "html-loader"
},
{
test: /\.(png|jpg|jpeg|gif)$/,
loader: "file-loader",
options: {
name: '[path][name].[ext]',
}
}
]
},
plugins: [
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: dev ? [] : ["**/*"]
}),
new CustomFunctionsMetadataPlugin({
output: "functions.json",
input: "./src/functions/functions.ts"
}),
new EnvironmentPlugin({
NODE_ENV: env.NODE_ENV || 'local'
}),
new HtmlWebpackPlugin({
filename: "functions.html",
template: "./src/functions/functions.html",
chunks: ["polyfill", "functions"]
}),
new CopyWebpackPlugin([
{
to: "[name]." + buildType + ".[ext]",
from: "manifest*.xml",
transform(content) {
if (dev) {
return content;
} else {
return content.toString().replace(new RegExp(urlDev, "g"), urlProd);
}
}
}
]),
new HtmlWebpackPlugin({
filename: "commands.html",
template: "./src/commands/commands.html",
chunks: ["polyfill", "commands"]
})
],
devServer: {
headers: {
"Access-Control-Allow-Origin": "*"
},
https: (options.https !== undefined) ? options.https : await devCerts.getHttpsServerOptions(),
port: process.env.npm_package_config_dev_server_port || 4000
}
};
return config;
};
Main.ts File:
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store/index";
import vuetify from "./plugins/vuetify";
Vue.config.productionTip = false;
/* eslint-disable-next-line #typescript-eslint/no-explicit-any */
(window as any).Office.onReady(() => {
new Vue({
router,
store,
vuetify,
render: (h) => h(App),
}).$mount("#app");
});
tsconfig.json - add-in
{
"compilerOptions": {
"allowJs": true,
"baseUrl": ".",
"esModuleInterop": true,
"experimentalDecorators": true,
"jsx": "react",
"module": "commonjs",
"noEmitOnError": true,
"outDir": "lib",
"resolveJsonModule": true,
"sourceMap": true,
"target": "es5",
"lib": [
"es2015",
"dom"
]
},
"exclude": [
"node_modules",
"dist",
"lib",
"lib-amd"
]
}
tsconfig.json - taskpane
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"experimentalDecorators": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env",
"node"
],
"paths": {
"#/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}
The Add-In folder holds the custom functions and the Taskpane folder holds the Vuejs app. I have left out other default files and added these because I believe they will help communicate my possible issue.
Steps To Merge:
I have edited Manifest.xml following the steps provided on Microsofts documentation.
Updated name to use SharedRuntime
<Set Name="SharedRuntime" MinVersion="1.1"/>
Added Runtimes tags within the Host tag
<Runtimes>
<Runtime resid="Taskpane.Url" lifetime="long" />
</Runtimes>
Updated the Page tag to use Taskpane.Url
<Page>
<SourceLocation resid="Taskpane.Url"/>
</Page>
Updated the FunctionFile tag with Taskpane.Url
<FunctionFile resid="Taskpane.Url"/>
In webpack.config.js:
I have removed the HtmlWebpackPlugin references and replaced with the following.
new HtmlWebpackPlugin({
filename: "index.html",
template: "../taskpane/public/index.html",
chunks: ["polyfill", "taskpane", "commands", "functions"]
})
Steps I did not provided in the Documentation:
Since the project was created using the yeoman office generator with the customfunctions option selected, I believe I needed to add the following to the webpack.config.js file's entry object:
entry: {
functions: "./src/functions/functions.ts",
polyfill: "#babel/polyfill",
commands: "./src/commands/commands.ts",
taskpane: "../taskpane/src/main.ts" <----- new addition
Problem:
When I try to build the project it throws errors such as:
ERROR in ../taskpane/src/main.ts
Module build failed
Error: TypeScript emitted no output for main.ts
Module not found errors
Property doesn't exist errors
More Info:
I'm thinking (but would love to confirm) that the steps I took to create the shared runtime provided by the documentation are indeed correct, along with adding the taskpane file to the entry object in the webpack config. But I just can't figure out why it won't compile. I'm thinking it has to do with the different tsconfig.json configurations. The addin is using target: "es5" while taskpane is using target: "esnext". There are other differences as well. If somebody can help me with this and needs that information, I will be more than happy to add it.

using ts-loader to run emitDeclarationOnly

currently i am using bable-loader to generate the javascript from typescript. but i want to generate typescript declarations as well.
to solve this originally i simply added tsc --emitDeclarationOnly at the end of our build script.
this approach works for building but not for watch
hence i wanted to still use the ts-loader just of emitDeclarationsOnly. how ever i kept getting the following error
lerna ERR! yarn run build stdout:
$ cross-env NODE_ENV=production webpack --config ./webpack.config.js --mode production
assets by status 122 KiB [cached] 117 assets
./src/index.ts 39 bytes [built]
ERROR in ./src/index.ts
Module build failed (from ./node_modules/ts-loader/index.js):
Error: TypeScript emitted no output for G:\SOMEPATH\src\index.ts.
at makeSourceMapAndFinish (G:\SOMEPATH\node_modules\ts-loader\dist\index.js:53:18)
at successLoader (G:\SOMEPATH\node_modules\ts-loader\dist\index.js:40:5)
at Object.loader (G:\SOMEPATH\node_modules\ts-loader\dist\index.js:23:5)
webpack 5.11.1 compiled with 1 error in 8620 ms
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
my tsconfig is
{
"compilerOptions": {
"alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
"declaration": true,
"declarationMap": true,
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"emitDeclarationOnly": true,
"lib": ["ESNext", "DOM"],
"module": "esnext",
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
"useDefineForClassFields": true,
"outDir": "./dist/",
"sourceMap": true,
"strict": true, /* Enable all strict type-checking options. */
"strictFunctionTypes": true, /* Enable strict checking of function types. */
"strictNullChecks": true, /* Enable strict null checks. */
"strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
"target": "es2015",
"types": []
/* Module Resolution Options */
},
"exclude": ["node_modules"],
"files": [
"./src/index.ts",
"./src/index.d.ts",
]
}
webpack
/* eslint-disable #typescript-eslint/no-var-requires */
const path = require('path');
const isProduction = process.env.NODE_ENV === 'production';
module.exports = {
cache: {
type: 'filesystem',
},
devtool: isProduction ? 'source-map' : 'source-map',
entry: './src/index.ts',
module: {
rules: [
{
enforce: 'pre',
exclude: /node_modules/,
test: /\.(ts|tsx)$/,
use: [
{
loader: require.resolve('eslint-loader'),
options: {
eslintPath: require.resolve('eslint'),
},
},
],
},
{
exclude: /node_modules/,
use: ['ts-loader'],
},
{
exclude: /node_modules/,
test: /\.tsx?$/,
use: ['babel-loader'],
},
],
},
output: {
filename: 'index.js',
globalObject: 'this',
library: 'data',
libraryTarget: 'umd',
path: path.resolve(__dirname, 'dist'),
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
};
You can use this plugin to suppress the error message.
/**
* ts-loader emits an error when no output is generated. This occurs when using Typescript's emitDeclarationOnluy
* flag. This plugin suppresses that error so that webpack will consider it a clean build.
*/
class EmitDeclarationOnly {
apply(compiler) {
compiler.hooks.shouldEmit.tap('EmitDeclarationOnly', (compilation) => this.handleHook(compiler, compilation));
}
handleHook(compiler, compilation){
compilation.errors = compilation.errors.filter((error) => {!error.toString().includes("TypeScript emitted no output for")});
}
}
Usage:
yourWebpackConfig.plugins = [new EmitDeclarationOnly()];

Use ESLint plugin only for some files/directories

I'm using the ESLint plugin for Jest to lint my Jest tests. The structure of my project is
my-project
|
|--tests
|
|--unit
|
|--e2e
I only want to use the Jest plugin when linting files in the tests/unit dir (because the files in tests/e2e are not Jest tests), but when I run the linting, this plugin is applied to all files under tests/unit, which results in spurious errors in the tests/e2e files.
I can disable individual rules in the tests/e2e dir by adding the following to eslintrc.js
module.exports = {
root: true,
env: {
node: true,
'jest/globals': true
},
extends: [
'eslint:recommended',
'plugin:jest/recommended',
],
parserOptions: {
parser: 'babel-eslint'
},
plugins: ['jest'],
"overrides": [
{
"files": ["tests/e2e/*.js"],
"rules": {
"jest/no-disabled-tests": "off",
"jest/expect-expect": "off",
"jest/valid-expect-in-promise": "off"
}
}
]
}
But rather than disabling individual rules in the tests/e2e dir, I would like to disable the Jest plugin completely.
From the eslint docs regarding overrides:
A glob specific configuration works almost the same as any other ESLint config. Override blocks can contain any configuration options that are valid in a regular config, with the exception of root and ignorePatterns.
Credit to the SO answer that helped me: Eslint allow multiple parsers based on glob patterns
The example in that answer also demonstrates overriding plugins.
My example uses two overrides sections, one for JavaScript files and one for TypeScript. This could easily be two different directories.
{
"overrides": [
{
"files": "**/*.ts",
"plugins": [
"prettier",
"#typescript-eslint"
],
"extends": [
"eslint-config-prettier",
"prettier",
"prettier/#typescript-eslint",
"plugin:import/errors",
"plugin:import/warnings",
"plugin:import/typescript",
"plugin:#typescript-eslint/recommended",
"plugin:#typescript-eslint/recommended-requiring-type-checking",
"plugin:prettier/recommended"
],
"parser": "#typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
},
"rules": {
}
},
{
// Disabling TypeScript lint rules for JS files.
"files": "**/*.js",
"plugins": [
"prettier"
],
"extends": [
"esnext",
"eslint-config-prettier",
"prettier",
"plugin:import/errors",
"plugin:import/warnings",
"plugin:prettier/recommended"
],
"parser": "babel-eslint",
"parserOptions": {
},
"env": {
"node": true
},
"rules": {
}
}
]
}
Encountered the same issue and haven't found a built in solution in eslint's config files, but you can try something that worked for me: ignore the E2E tests pattern in the main eslintrc.js and create another eslintrc.js file nested in the E2E directory.
as follows:
my-project
|-- eslintrc.js // this is your main eslint config
|--tests
|
|--unit
|
|--e2e
|
|-- eslintrc.js // nested eslintrc without the "jest" plugin
Note that you would have to tell the babel-eslint parser in the nested eslintrc where the babel config files is (usually as part of the parserOptions) since it is no longer in the same directory.
Main eslintrc.js:
module.exports = {
root: true,
env: {
node: true,
'jest/globals': true
},
extends: [
'eslint:recommended',
'plugin:jest/recommended',
],
parser: 'babel-eslint'
plugins: ['jest'],
ignorePatterns: ["tests/e2e/*.js"]
}
Nested eslintrc.js file in tests/e2e/:
module.exports = {
root: true,
env: {
node: true
},
extends: ['eslint:recommended'],
parser: 'babel-eslint',
parserOptions: {
babelOptions: {
configFile: '../../babel.config.js' // assuming this is the name of your babel config file in the project root
}
}
}
You can use ignorePatterns in your config file or create a .eslintignore file.
See: https://eslint.org/docs/user-guide/configuring#ignoring-files-and-directories

How to implement flowtype in Nuxt.js

I am currently trying to convert our existing vue.js project into nuxt.js. I am unable to add flowtype support in nuxt.js. when i run the flow server it says no errors!! but running npm run dev, its throwing error on the flow syntax.
.flowconfig
[include]
pages/**/.*
components/**/.*
layouts/**/.*
apiRoutes/.*
store/.*
utils/.*
[ignore]
.*/build/.*
.*/config/.*
.*/dist/.*
.*/node_modules/.*
.*/static/.*
.*/test/.*
.*/ssl/.*
.*/.nuxt/.*
[libs]
./flow/
[options]
emoji=true
module.file_ext=.vue
module.file_ext=.js
server.max_workers=3
log.file=./flow.log
suppress_comment= \\(.\\|\n\\)*\\$FlowFixMe
unsafe.enable_getters_and_setters=true
module.system.node.resolve_dirname=node_modules
module.name_mapper='^.*\.css$' -> 'empty/object'
module.name_mapper='^.*\.js$' -> 'empty/object'
module.name_mapper='^#/\(.*\)$' -> '<PROJECT_ROOT>/\1'
i've added all the neccessary babel and eslint packages.
.babelrc
{
"presets": [
["env", { "modules": false }],
"stage-2",
["es2015", {"modules": false }],
"flow-vue"
],
"plugins": [
"transform-runtime",
"transform-class-properties",
"syntax-flow",
"transform-flow-strip-types"
],
"comments": false,
"env": {
"test": {
"presets": ["env", "stage-2"],
"plugins": [ "istanbul" ]
}
}
}
.eslintrc.js
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint',
sourceType: 'module'
},
env: {
browser: true,
node: true,
jquery: true
},
extends: [
'standard',
'plugin:flowtype/recommended'
// 'plugin:vue/recommended'
],
// required to lint *.vue files
plugins: [
'html',
'flowtype-errors',
'flowtype'
],
// add your custom rules here
rules: {
'flowtype-errors/show-errors': 2,
// allow paren-less arrow functions
'arrow-parens': 0,
'semi': ["error", "always"],
// allow async-await
'generator-star-spacing': 0
},
globals: {}
}
On running npm run dev, it doesnt parse flowtype syntax
I suggest following the instructions on the flow website to set up Babel. In particular there is a preset, so you shouldn't need to configure individual rules. Then you'll actually need to run Babel (again, instructions are on the website). Once you have run Babel, you should be able to run the code it outputs in Node.

Categories

Resources