Can not use serverSideTranslations on Vercel - next.js

In my index page i'm using serverSideTranslations function. getting error about finding file of translation.
this error happens only on pages that used by serverSideTranslations.
I deployed to Vercel and Netlify. in both of them i'v got the same error.
in _app.js i'm using appWithTranslation.
Dependencies:
"dependencies": {
"#fortawesome/fontawesome-free": "^5.15.4",
"#netlify/plugin-nextjs": "^3.9.2",
"axios": "^0.21.1",
"bootstrap": "^4.6.0",
"dayjs": "^1.10.4",
"dotenv": "^8.2.0",
"fs-extra": "^10.0.0",
"is-mobile": "^3.0.0",
"next": "^11.1.2",
"next-i18next": "^8.9.0",
"next-seo": "^4.20.0",
"node-fetch": "^2.6.1",
"parse": "^3.1.0",
"react": "17.0.1",
"react-bootstrap": "^1.5.0",
"react-dom": "17.0.1",
"react-infinite-scroller": "^1.2.4",
"recoil": "^0.1.2",
"sass": "^1.43.2",
"ts-node": "^9.1.1"
}
next.config.js
const path = require('path');
const { PHASE_DEVELOPMENT_SERVER } = require('next/constants')
const i18NextConfig = require('./next-i18next.config');
const prodConfig = {
generateBuildId: () => 'build-id',
compress: true,
target: 'serverless',
i18n: i18NextConfig.i18n,
sassOptions: {
includePaths: [path.join(__dirname, 'styles')],
},
}
module.exports = (phase, { defaultConfig }) => {
if (phase === PHASE_DEVELOPMENT_SERVER) {
return {
...defaultConfig,
...prodConfig,
compress: false,
}
}
return prodConfig;
}
next-i18next.config.js
const path = require('path');
module.exports = {
i18n: {
defaultLocale: 'he',
locales: ['he'],
localePath: path.resolve('./locales'), // <<< i tried to put this line here
},
keySeparator: '>',
nsSeparator: '|',
reloadOnPrerender: false,
localePath: path.resolve('./locales'), // <<< and also here
};
Error message from Vercel lambda function
ng request: Error: ENOENT: no such file or directory, scandir '/var/task/public/locales/he'
at Object.readdirSync (fs.js:1043:3)
at getLocaleNamespaces (/var/task/node_modules/next-i18next/dist/commonjs/config/createConfig.js:175:23)
at /var/task/node_modules/next-i18next/dist/commonjs/config/createConfig.js:181:20
at Array.map ()
at getNamespaces (/var/task/node_modules/next-i18next/dist/commonjs/config/createConfig.js:180:44)
at createConfig (/var/task/node_modules/next-i18next/dist/commonjs/config/createConfig.js:221:29)
at _callee$ (/var/task/node_modules/next-i18next/dist/commonjs/serverSideTranslations.js:199:53)
at tryCatch (/var/task/node_modules/regenerator-runtime/runtime.js:63:40)
at Generator.invoke [as _invoke] (/var/task/node_modules/regenerator-runtime/runtime.js:294:22)
at Generator.next (/var/task/node_modules/regenerator-runtime/runtime.js:119:21) {
errno: -2,
syscall: 'scandir',
path: '/var/task/public/locales/he'
}

You should modify next-i18next.config.js file in your project, and add path.resolve to locale path. You can see an example in this repo. Make sure that you know where your locale folder is located, and write the correct path.
The answer to this issue was found in this github thread.

Note(Vercel and Netlify)
Some serverless PaaS may not be able to locate the path of your translations and require additional configuration. If you have filesystem issues using serverSideTranslations, set config.localePath to use path.resolve.
Solution
You have to set config.locationPath into the next-i18next.config.js file.
For example,
// next-i18next.config.js
const path = require("path");
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr'],
},
// Path to the translation files
// i.e., ./public/locales/en.json, ./public/locales/fr.json
localePath: path.resolve("./public/locales"),
}
For more information please refer to the documentation.

Related

Next.js 12 Migration and Eslint configuration with Prettier, Airbnb, Jest/react-testing-library

UPDATE: Finally got the config and dep versions to work. I updated my files below in case someone else is having the same issues.
I'm migrating a large app from Next.js 10 to v12. I had minor babel configuration, so decided to remove that, while also using Next.js's linter next lint. We initially used prettier and airbnb eslint plugins. Instead of the eslint-plugin-airbnb, I'm using eslint-plugin-airbnb-base. The reason being eslint-config-next already contains ESLint rules/plugins for eslint, eslint-plugin-import, eslint-plugin-react, eslint-plugin-react-hooks, and eslint-plugin-jsx-a11y, which is basically airbnb
My issue:
I have a small .prettierrc.js file, but the rules are not being applied.
ie: printwidth: 80
FIXED: Also getting this error Error: Definition for rule 'jest/expect-expect' was not found
I've been going in circles, some eyes or feedback would be greatly appreciated.
.eslintrc.json
module.exports = {
root: true,
plugins: ['simple-import-sort', 'unused-imports'],
extends: [
'next',
'next/core-web-vitals',
'plugin:jest/recommended',
'plugin:prettier/recommended',
],
settings: {
'import/resolver': {
alias: {
map: [['#', './']],
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
},
},
rules: { {.....},
"overrides: { ... typescript overrides },
jest.config.js
const nextJest = require('next/jest');
const createJestConfig = nextJest({
dir: './'
})
const customConfig = {
rootDir: './',
moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx'],
setupFilesAfterEnv: ['<rootDir>/test-utils/jest-setup.ts'],
moduleNameMapper: {
'#/(.*)$': '<rootDir>/$1',
},
moduleDirectories: ['node_modules', '<rootDir>/'],
testEnvironment: 'jest-environment-jsdom',
};
module.exports = createJestConfig(customConfig);
prettierrc
module.exports = {
bracketSpacing: true,
printWidth: 80,
singleQuote: true,
trailingComma: 'es5',
arrowParens: 'avoid',
};
package.json
"devDependencies": {
"#cypress/code-coverage": "^3.9.10",
"#hookform/devtools": "^4.0.1",
"#next/eslint-plugin-next": "^12.3.1",
"#swc/core": "^1.3.3",
"#swc/jest": "^0.2.23",
"#testing-library/cypress": "^8.0.0",
"#testing-library/jest-dom": "^5.16.5",
"#testing-library/react": "^13.2.0",
"#testing-library/react-hooks": "^8.0.1",
"#types/autosuggest-highlight": "^3.1.1",
"#types/cookie": "^0.4.1",
"#types/geojson": "^7946.0.8",
"#types/google.maps": "^3.45.6",
"#types/jest": "^26.0.22",
"#types/js-cookie": "^2.2.6",
"#types/lodash.throttle": "^4.1.6",
"#types/mui-datatables": "^3.7.6",
"#types/qs": "^6.9.6",
"#types/react": "17.0.2",
"#types/react-dom": "17.0.2",
"#types/react-gtm-module": "^2.0.1",
"#types/react-input-mask": "^3.0.1",
"#types/react-swipeable-views": "^0.13.1",
"#types/stripe-v2": "^2.0.2",
"#typescript-eslint/eslint-plugin": "^5.30.0",
"cross-env": "^7.0.3",
"cypress": "^8.6.0",
"eslint": "^8.21.0",
"eslint-config-next": "^12.3.1",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-cypress": "^2.11.3",
"eslint-plugin-jest": "^27.0.4",
"eslint-plugin-jest-dom": "^4.0.2",
"eslint-plugin-simple-import-sort": "^5.0.3",
"execa": "^4.0.3",
"husky": "^4.2.5",
"jest": "^29.1.2",
"jest-environment-jsdom": "^29.1.2",
"jest-junit": "^12.2.0",
"lint-staged": "^10.5.1",
"pg-promise": "^10.6.2",
"prettier": "^2.7.1",
"react-test-renderer": "^18.0.0",
"ts-jest": "^29.0.3",
"typescript": "^4.5.5"
},
.lintstagedrc.js
const path = require('path')
const buildEslintCommand = (filenames) =>
`next lint --fix --file ${filenames
.map((f) => path.relative(process.cwd(), f))
.join(' --file ')}`
module.exports = {
'*.{js,jsx,ts,tsx}': [buildEslintCommand],
}
If you want to run prettier as part of your linting process, you need eslint-plugin-prettier. I see you have both eslint-plugin-prettier and eslint-config-prettier. They do slightly different things so check their docs and stick to one of them. Personally, I prefer eslint-config-prettier, so I separate the linting from the formatting, but this is a personal choice!
You need to install eslint-plugin-jest, then enable it in the plugins section of your ESLint config.
If you are happy with Next.js ESLint config, you should check Vercel Style Guide, which includes sensible defaults for ESLint, prettier and TypeScript.

Datatables.net (1.10.22) + Webpack Encore (1.11) + Symfony (5.2.6)

I am working on a Symfony 5.2.6 project and I am trying to use datatables.net library in my project, but can't find a way to import it properly.
I am using a lot of js/jquery libraries and everything is working well except datatables.
(I am using Metronic admin template)
This is my webpack.config.js :
const Encore = require('#symfony/webpack-encore');
const CopyWebpackPlugin = require('copy-webpack-plugin');
if (!Encore.isRuntimeEnvironmentConfigured()) {
Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
}
Encore
.setOutputPath('public/build/')
.setPublicPath('/build')
.addStyleEntry('basecss', './assets/sass/style.scss')
.addStyleEntry('pluginscss', './assets/plugins/plugins.scss')
.addStyleEntry('extrascss', './assets/css/extras.css')
.addEntry('app', './assets/app.js')
.addEntry('plugins', './assets/plugins/plugins.js')
.addEntry('scripts', './assets/scripts.js')
.addEntry('test', './assets/test.js')
.addEntry('page-ms-liste', './assets/pages/matiereseche/liste.js')
.addStyleEntry('page-login-css', './assets/pages/authentication/login.css')
.enableStimulusBridge('./assets/controllers.json')
.splitEntryChunks()
.enableSingleRuntimeChunk()
.cleanupOutputBeforeBuild()
.enableBuildNotifications()
.enableSourceMaps(!Encore.isProduction())
.enableVersioning(Encore.isProduction())
.configureBabel((config) => {
config.plugins.push('#babel/plugin-proposal-class-properties');
})
.configureBabelPresetEnv((config) => {
config.useBuiltIns = 'usage';
config.corejs = 3;
})
// enables Sass/SCSS support
.enableSassLoader()
.addPlugin(new CopyWebpackPlugin({
patterns: [
{ from: './assets/images', to: 'images' }
],
}))
.addLoader({
test: require.resolve('jquery'),
use: [{
loader: 'expose-loader',
options: {
exposes: [
{
globalName: "$",
override: true,
},
{
globalName: "jQuery",
override: true,
}
]
}
}]})
.addLoader({
test: '/datatables\.net.*/',
use: [{
loader: 'imports-loader',
options: {
imports: {
moduleName: 'jquery',
name: '$',
},
additionalCode: "var define = false;"
}
}]})
;
const config = Encore.getWebpackConfig();
module.exports = config;
I also tried to use .autoProvidejQuery()
Inside my scripts.js I have :
window.jQuery = window.$ = require('jquery');
// ...
require('datatables.net');
require('datatables.net-bs4');
Then in my js file :
var t = $("#datatable");
t.DataTable(.....)
The error :
Uncaught TypeError: $(...).DataTable is not a function
I found a lot of threads on this topic, but I tried everything without success (using loaders, ...)
I also tried to import jquery from CDN and datatables too, but I have a jquery issue (jquery undefined)
If someone has an idea...
Thank you.
Remove
window.jQuery = window.$ = require('jquery');
Then, you can import datatable this way:
import $ from "jquery";
require('datatables.net-bs4')( window, $ );
This way, DataTable should be recognized and you will be able to use it.
After quite some time testing various answers from Stackoverflow, I managed to make it work (with the help of Guillaume F. and Dylan Kas).
These are the files :
webpack.config.js
const Encore = require('#symfony/webpack-encore');
const CopyWebpackPlugin = require('copy-webpack-plugin');
if (!Encore.isRuntimeEnvironmentConfigured()) {
Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
}
Encore
.setOutputPath('public/build/')
.setPublicPath('/build')
// Main Js file
.addEntry('app', './assets/app.js')
// In my case Datatable init code is in this file. Don't forget to load this asset from your template page with the shortcut : {{ encore_entry_script_tags('my-page') }}
.addEntry('my-page', './assets/pages/my-page.js')
//.. Other imports here ..
/*.addEntry('scripts', './assets/scripts.js')*/
.splitEntryChunks()
.enableSingleRuntimeChunk()
.cleanupOutputBeforeBuild()
.enableBuildNotifications()
.enableSourceMaps(!Encore.isProduction())
.enableVersioning(Encore.isProduction())
.configureBabel((config) => {
config.plugins.push('#babel/plugin-proposal-class-properties');
})
.configureBabelPresetEnv((config) => {
config.useBuiltIns = 'usage';
config.corejs = 3;
})
.addPlugin(new CopyWebpackPlugin({
patterns: [
{ from: './assets/images', to: 'images' }
],
}))
;
const config = Encore.getWebpackConfig();
// Without this, I have issues with my DT.net requires
config.module.rules.unshift({
parser: {
amd: false,
}
});
module.exports = config;
My app.js file
window.jQuery = window.$ = require('jquery');
require('bootstrap');
window.Popper = require('popper.js').default;
// Needed form Datatables Buttons plugin
window.JSZip = require('jszip');
const pdfMake = require('pdfmake/build/pdfmake.js');
const pdfFonts = require('pdfmake/build/vfs_fonts.js');
pdfMake.vfs = pdfFonts.pdfMake.vfs;
require('datatables.net')(window, $);
require('datatables.net-bs4')(window, $);
require('datatables.net-buttons/js/dataTables.buttons.min.js')(window, $);
require('datatables.net-buttons-bs4')(window, $);
require('datatables.net-buttons/js/buttons.flash.js')(window, $);
require('datatables.net-buttons/js/buttons.html5.js')(window, $);
require('datatables.net-buttons/js/buttons.print.js')(window, $);
My packages.json :
{
"dependencies": {
// others imports above
"bootstrap": "^4.6.0",
"datatables.net": "^1.10.24",
"datatables.net-autofill-bs4": "^2.3.5",
"datatables.net-bs4": "1.10.24",
"datatables.net-buttons-bs4": "^1.7.0",
"datatables.net-colreorder-bs4": "^1.5.2",
"datatables.net-fixedcolumns-bs4": "^3.3.2",
"datatables.net-fixedheader-bs4": "^3.1.7",
"datatables.net-keytable-bs4": "^2.5.3",
"datatables.net-responsive-bs4": "^2.2.6",
"datatables.net-rowgroup-bs4": "^1.1.2",
"datatables.net-rowreorder-bs4": "^1.2.7",
"datatables.net-scroller-bs4": "^2.0.3",
"datatables.net-select-bs4": "^1.3.1",
"jquery": "^3.6.0",
"jszip": "^3.5.0",
"pdfmake": "^0.1.36",
"popper.js": "^1.16.1",
},
"devDependencies": {
"#symfony/stimulus-bridge": "^2.0.0",
"#symfony/webpack-encore": "^1.0.0",
"copy-webpack-plugin": "^8.1.0",
"core-js": "^3.0.0",
"expose-loader": "^2.0.0",
"imports-loader": "^2.0.0",
"lodash": "^4.17.13",
"regenerator-runtime": "^0.13.2",
"sass": "^1.32.8",
"sass-loader": "11.0.0",
"script-loader": "^0.7.2",
"stimulus": "^2.0.0",
"webpack-notifier": "^1.6.0"
},
"license": "UNLICENSED",
"private": true,
"scripts": {
"dev-server": "encore dev-server",
"dev": "encore dev",
"watch": "encore dev --watch",
"build": "encore production --progress"
}
}
and in the end my file initializing the datatable (I use one entry js file per page):
page.js
"use strict";
var MyPage = {
init: function () {
const table = $('#datatable').DataTable({
buttons: [
{
extend: 'print',
exportOptions: {
columns: [0, 1, 2, 3]
}
},
{
extend: 'excelHtml5',
exportOptions: {
columns: [0, 1, 2, 3]
}
},
],
columnDefs: [
{
width: '75px',
targets: 4,
},
],
});
$('#export_print').on('click', function(e) {
e.preventDefault();
table.button(0).trigger();
});
$('#export_excel').on('click', function(e) {
e.preventDefault();
table.button(1).trigger();
});
},
};
jQuery(document).ready(function () {
MyPage.init();
});
Note that in my case I toggle the buttons from 2 html elements.

Browsersync keeps reloading

I have Gulp + Browsersync working with Wordpress.
Everything was working well, reloading every time I change files.
But since yesterday only, Browsersync keeps reloading without any reason.
I didn't made any changes on my gulpfile. I tried reverting to a former commit from 2 days ago, same thing. I don't know where it comes from.
Here's my repo.
I tried :
downgrading browsersync to 2.24.4 from this post
adding this to gulp :
socket: {
clients: {
heartbeatTimeout: 60000
}
},
Here are my files.
gulpfile.babel.js
import { src, dest, watch, series, parallel } from 'gulp';
import yargs from 'yargs';
import sass from 'gulp-sass';
import cleanCss from 'gulp-clean-css';
import gulpif from 'gulp-if';
import postcss from 'gulp-postcss';
import sourcemaps from 'gulp-sourcemaps';
import autoprefixer from 'autoprefixer';
import imagemin from 'gulp-imagemin';
import del from 'del';
import webpack from 'webpack-stream';
import named from 'vinyl-named';
import browserSync from 'browser-sync';
import zip from 'gulp-zip';
import info from './package.json';
import replace from 'gulp-replace';
import wpPot from 'gulp-wp-pot';
import tailwindcss from 'tailwindcss';
// import purgeCss from 'gulp-purgecss';
const PRODUCTION = yargs.argv.prod;
export const clean = () => del(['dist']);
export const styles = () => {
return (
src('src/scss/app.scss')
.pipe(gulpif(!PRODUCTION, sourcemaps.init()))
.pipe(sass().on('error', sass.logError))
.pipe(postcss([tailwindcss('./tailwind.config.js')]))
.pipe(gulpif(PRODUCTION, postcss([autoprefixer])))
.pipe(gulpif(PRODUCTION, cleanCss({ compatibility: 'ie8' })))
// .pipe(
// gulpif(
// PRODUCTION,
// purgeCss({
// content: ['**/*.php']
// })
// )
// )
.pipe(gulpif(!PRODUCTION, sourcemaps.write()))
.pipe(dest('dist/css'))
.pipe(server.stream())
);
};
export const images = () => {
return src('src/images/**/*.{jpg,jpeg,png,svg,gif}')
.pipe(gulpif(PRODUCTION, imagemin()))
.pipe(dest('dist/images'));
};
export const copy = () => {
return src(['src/**/*', '!src/{images,js,scss}', '!src/{images,js,scss}/**/*']).pipe(
dest('dist')
);
};
export const watchForChanges = () => {
watch('src/scss/**/*.scss', styles);
watch('src/images/**/*.{jpg,jpeg,png,svg,gif}', series(images, reload));
watch(['src/**/*', '!src/{images,js,scss}', '!src/{images,js,scss}/**/*'], series(copy, reload));
watch('src/js/**/*.js', series(scripts, reload));
watch('**/*.php', reload);
};
export const scripts = () => {
return src(['src/js/bundle.js'])
.pipe(named())
.pipe(
webpack({
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
}
]
},
mode: PRODUCTION ? 'production' : 'development',
devtool: !PRODUCTION ? 'inline-source-map' : false,
output: {
filename: '[name].js'
}
})
)
.pipe(dest('dist/js'));
};
/***** Generating a POT file *****/
export const pot = () => {
return src('**/*.php')
.pipe(
wpPot({
domain: 'boosters',
package: info.name
})
)
.pipe(dest(`languages/${info.name}.pot`));
};
/***** Compress theme into a ZIP file after renaming _themename *****/
export const compress = () => {
return src([
'**/*',
'!node_modules{,/**}',
'!bundled{,/**}',
'!src{,/**}',
'!.babelrc',
'!.gitignore',
'!gulpfile.babel.js',
'!package.json',
'!package-lock.json'
])
.pipe(
gulpif(
// prevent bug if there are zip files inside the theme
file => file.relative.split('.').pop() !== 'zip',
replace('boosters', info.name)
)
)
.pipe(zip(`${info.name}.zip`))
.pipe(dest('bundled'));
};
/****** BrowserSync ******/
const server = browserSync.create();
export const serve = done => {
server.init({
proxy: 'localhost:8888/boosters', // put your local website link here
snippetOptions: {
ignorePaths: 'boosters/wp-admin/**'
},
ghostMode: false
// socket: {
// clients: {
// heartbeatTimeout: 60000
// }
// },
// logLevel: 'debug',
// logFileChanges: true,
// logConnections: true
});
done();
};
export const reload = done => {
server.reload();
done();
};
/****** Series & Parallel Scripts ******/
export const dev = series(clean, parallel(styles, images, scripts, copy), serve, watchForChanges);
export const build = series(clean, parallel(styles, images, scripts, copy), pot, compress);
export default dev;
package.json
{
"name": "boosters",
"version": "1.0.0",
"description": "A Wordpress website for Boost.rs by DoubleCat Studio",
"main": "gulpfile.babel.js",
"scripts": {
"start": "gulp",
"build": "gulp build --prod"
},
"repository": {
"type": "git",
"url": "git+ssh://git#github.com/indaviande/boosters.git"
},
"author": "Vianney Bernet",
"license": "ISC",
"bugs": {
"url": "https://github.com/indaviande/boosters/issues"
},
"browserslist": [
"last 4 version",
"> 1%",
"ie 11"
],
"homepage": "https://github.com/indaviande/boosters#readme",
"devDependencies": {
"#babel/core": "^7.4.3",
"#babel/preset-env": "^7.4.3",
"#babel/register": "^7.4.0",
"autoprefixer": "^9.5.1",
"babel-loader": "^8.0.5",
"browser-sync": "^2.26.7",
"del": "^4.1.0",
"gulp": "^4.0.0",
"gulp-clean-css": "^4.0.0",
"gulp-if": "^2.0.2",
"gulp-imagemin": "^5.0.3",
"gulp-postcss": "^8.0.0",
"gulp-replace": "^1.0.0",
"gulp-sass": "^4.0.2",
"gulp-sourcemaps": "^2.6.5",
"gulp-wp-pot": "^2.3.5",
"gulp-zip": "^4.2.0",
"tailwindcss": "^1.0.4",
"vinyl-named": "^1.1.0",
"webpack-stream": "^5.2.1",
"yargs": "^13.2.2"
},
"dependencies": {
"tar": ">4.4.7"
}
}
Browsersync has a log that you can inspect to see which files are being changed that trigger the reload. You can also increase specificity of what you're watching/ignoring. Start off small and gradually increase your glob paths until you can see reloads on all changes.
server.init({
logLevel: 'debug',
files: [
'wp-content/themes/**/*.css',
'wp-content/themes/**/*.js',
'wp-content/themes/**/*.php',
],
ignore: [
'folder-to-ignore/**/*.*'
]
});

dotenv values not loaded in nextjs

I am struggling to load my .env file in my NextJS app. Here is my code:
My .env is in root /
My index.js is in /pages/index.js
Here is my index.js:
require("dotenv").config({ path: __dirname + '/../.env' })
import React, {Component} from 'react'
import Layout from '../components/layout'
import axios from 'axios'
class Import extends Component{
uploadCSV = (evt) => {
evt.preventDefault();
const uploadURL = process.env.MY_UPLOAD_URL
let data = new FormData(evt.target)
axios.post(uploadURL, data, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then((res) => {
console.log(res)
})
}
render() {
return (
<div>
<Layout title="Import Chatbot Intents" description="Import Chatbot Intents">
<form onSubmit={this.uploadCSV} name="import_csv" className="import_csv">
<h2>Import CSV</h2>
<div className="form-group">
<label htmlFor="csv_file">Upload file here: </label>
<input type="file" name="csv_file" id="csv_file" ref="csv_file" />
</div>
<div className="form-group">
<input type="hidden" id="customer_id" name="customer_id" ref="customer_id" value="1"/>
<button className="btn btn-success">Submit</button>
</div>
</form>
</Layout>
</div>
)
}
}
export default Import
I observe that I can print out .env content in render() function, but I cannot do that in uploadCSV function.
For your info:
using just require("dotenv").config() doesn't work
using require("dotenv").config({path: "../"}) doesn't work
Updated
My env-config.js:
module.exports = {
'CSV_UPLOAD_URL': "http://localhost:3000/uploadcsv"
}
My babel.config.js:
const env = require('./env-config')
console.log(env)
module.exports = function(api){
// console.log({"process": process.env})
api.cache(false)
const presets = [
"next/babel",
"#zeit/next-typescript/babel"
]
const plugins = [
"#babel/plugin-transform-runtime",
[
'transform-define',
env
]
]
return { presets, plugins }
}
My package.json
{
"name": "Botadmin",
"scripts": {
"dev": "next -p 3001",
"build": "next build",
"start": "next start"
},
"dependencies": {
"#babel/runtime": "^7.1.5",
"#zeit/next-less": "^1.0.1",
"#zeit/next-typescript": "^1.1.1",
"#zeit/next-workers": "^1.0.0",
"axios": "^0.18.0",
"forever": "^0.15.3",
"less": "^3.8.1",
"multer": "^1.4.1",
"next": "7.0.2",
"nprogress": "^0.2.0",
"papaparse": "^4.6.2",
"react": "16.6.3",
"react-dom": "16.6.3",
"typescript": "^3.1.6",
"worker-loader": "^2.0.0"
},
"devDependencies": {
"#babel/plugin-transform-runtime": "^7.1.0",
"babel-plugin-transform-define": "^1.3.0",
"dotenv": "^6.1.0",
"fork-ts-checker-webpack-plugin": "^0.4.15"
}
}
The Error:
Module build failed (from ./node_modules/next/dist/build/webpack/loaders/next-babel-loader.js):
TypeError: Property property of MemberExpression expected node to be of a type ["Identifier","PrivateName"] but instead got "StringLiteral"
If you want to use env in Nextjs
Install babel-plugin-transform-define
create the env-config.js file and define your variables
const prod = process.env.NODE_ENV === 'production'
module.exports = {
'process.env.BACKEND_URL': prod ? 'https://api.example.com' : 'https://localhost:8080'
}
Create the .babelrc.js file
const env = require('./env-config.js')
module.exports = {
presets: ['next/babel'],
plugins: [['transform-define', env]]
}
Now you have access to the env in your code
process.env.BACKEND_URL
Alternatives: next-env
As of Next.js 9.4, there is a built-in solution for setting environment variables https://nextjs.org/docs/basic-features/environment-variables
Thanks for #Alex for the answer. Another way to solve the same problem is to install dotenv-webpack using npm install -D dotenv-webpack.
Once installed. edit next.config.js:
require('dotenv').config()
const Dotenv = require('dotenv-webpack')
const path = require('path')
const withTypescript = require('#zeit/next-typescript')
const withWorkers = require('#zeit/next-workers')
const withLess = require('#zeit/next-less')
module.exports = withWorkers(withLess(withTypescript({
context: __dirname,
generateEtags: false,
entry: './pages/index.js',
distDir: 'build',
pageExtensions: ['js', 'jsx', 'ts', 'tsx'],
cssModules: false,
webpack: (config, options) => {
config.plugins = config.plugins || []
config.plugins = [
...config.plugins,
// Read the .env file
new Dotenv({
path: path.join(__dirname, '.env'),
systemvars: true
})
]
// Fixes npm packages that depend on `fs` module
config.node = {
fs: 'empty'
}
return config
}
})))
I know I'm a bit late, but, you can just install dotenv and use it inside of your next.config.js file
require("dotenv").config();
const environment = process.env.NODE_ENV || "dev";
if you need to replicate next.js env loading in other files (setupTests.ts, next-logger.config.js) do this:
const { loadEnvConfig } = require('#next/env')
loadEnvConfig(__dirname, true, {
info: () => null,
error: console.error,
})

Angular 5/ASP.NET - “No ResourceLoader implementation has been provided. Can't read the URL”

I'm trying to build a new Angular5/ASP.NET SPA on Visual Studio 2017. Therefore i created a .NET Core->ASP.NET Core-Web Application with Angular, which results in a project containing an Angular4 sample application.
Running this application is no problem at all, the problems start when i try to go on Angular 5 (5.0.1 or 5.0.0, does not matter) with this application.
After doing all necessary steps, the app runs fine in Debug mode. But trying to build and start it in Release (or deploy it to azure) leads to the following error:
An unhandled exception occurred while processing the request.
NodeInvocationException: No ResourceLoader implementation has been provided. Can't read the url "app.component.html"
Error: No ResourceLoader implementation has been provided. Can't read the url "app.component.html"
at Object.get (E:\angular4_spielwiese\vs spielwiese\myAngularApp\myAngularApp\ClientApp\dist\vendor.js:98069:15)
at DirectiveNormalizer.module.exports.DirectiveNormalizer._fetch (E:\angular4_spielwiese\vs spielwiese\myAngularApp\myAngularApp\ClientApp\dist\vendor.js:44087:43)
at DirectiveNormalizer.module.exports.DirectiveNormalizer._preParseTemplate (E:\angular4_spielwiese\vs spielwiese\myAngularApp\myAngularApp\ClientApp\dist\vendor.js:44142:29)
at DirectiveNormalizer.module.exports.DirectiveNormalizer.normalizeTemplate (E:\angular4_spielwiese\vs spielwiese\myAngularApp\myAngularApp\ClientApp\dist\vendor.js:44122:36)
at CompileMetadataResolver.module.exports.CompileMetadataResolver.loadDirectiveMetadata (E:\angular4_spielwiese\vs spielwiese\myAngularApp\myAngularApp\ClientApp\dist\vendor.js:55794:75)
at E:\angular4_spielwiese\vs spielwiese\myAngularApp\myAngularApp\ClientApp\dist\vendor.js:74510:72
at Array.forEach (native)
at E:\angular4_spielwiese\vs spielwiese\myAngularApp\myAngularApp\ClientApp\dist\vendor.js:74509:72
at Array.forEach (native)
at JitCompiler.module.exports.JitCompiler._loadModules (E:\angular4_spielwiese\vs spielwiese\myAngularApp\myAngularApp\ClientApp\dist\vendor.js:74506:75)
Microsoft.AspNetCore.NodeServices.HostingModels.HttpNodeInstance+<InvokeExportAsync>d__7.MoveNext()
What i do for moving to Angular5 is:
Change Versions in package.json for all Angular-Modules to 5.0.1, also go to newer version for typescript, rxjs, angular/cli and #ngtools/webpack (1.5.0 -> 1.8.0)
So my new package.json looks like this:
{
"name": "myAngularApp",
"private": true,
"version": "0.0.0",
"scripts": {
"test": "karma start ClientApp/test/karma.conf.js"
},
"dependencies": {
"#angular/animations": "^5.0.1",
"#angular/common": "^5.0.1",
"#angular/compiler": "^5.0.1",
"#angular/core": "^5.0.1",
"#angular/forms": "^5.0.1",
"#angular/http": "^5.0.1",
"#angular/platform-browser": "^5.0.1",
"#angular/platform-browser-dynamic": "^5.0.1",
"#angular/platform-server": "^5.0.1",
"#angular/router": "^5.0.1",
"#types/webpack-env": "^1.13.0",
"angular2-template-loader": "^0.6.2",
"aspnet-prerendering": "^3.0.1",
"aspnet-webpack": "^2.0.1",
"awesome-typescript-loader": "^3.2.1",
"bootstrap": "^3.3.7",
"css": "^2.2.1",
"css-loader": "^0.28.7",
"es6-shim": "^0.35.3",
"event-source-polyfill": "0.0.9",
"expose-loader": "^0.7.3",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^1.1.5",
"html-loader": "^0.5.1",
"html-webpack-plugin": "^2.30.1",
"isomorphic-fetch": "^2.2.1",
"jquery": "^3.2.1",
"json-loader": "^0.5.4",
"preboot": "^5.1.7",
"raw-loader": "^0.5.1",
"reflect-metadata": "^0.1.10",
"rxjs": "^5.5.2",
"style-loader": "^0.19.0",
"to-string-loader": "^1.1.5",
"typescript": "^2.6.1",
"zone.js": "^0.8.18"
},
"devDependencies": {
"#angular/cli": "1.5.0",
"#angular/compiler-cli": "^5.0.1",
"#ngtools/webpack": "1.8.0",
"#types/chai": "4.0.1",
"#types/jasmine": "2.6.3",
"chai": "4.0.2",
"jasmine-core": "2.6.4",
"karma": "1.7.0",
"karma-chai": "0.1.0",
"karma-chrome-launcher": "2.2.0",
"karma-cli": "1.0.1",
"karma-jasmine": "1.1.0",
"karma-webpack": "2.0.3",
"url-loader": "0.6.2",
"webpack": "3.8.1",
"webpack-hot-middleware": "2.20.0",
"webpack-merge": "4.1.1"
}
}
Then i change AotPlugin in webpack.config.js to AngularCompilerPlugin
This is my webpack.config.js:
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const AngularCompilerPlugin = require('#ngtools/webpack').AngularCompilerPlugin;
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
module.exports = (env) => {
// Configuration in common to both client-side and server-side bundles
const isDevBuild = !(env && env.prod);
const sharedConfig = {
stats: { modules: false },
context: __dirname,
resolve: { extensions: [ '.js', '.ts' ] },
output: {
filename: '[name].js',
publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
module: {
rules: [
{ test: /\.ts$/, include: /ClientApp/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader'] : ['awesome-typescript-loader?silent=true', 'angular2-template-loader'] },// '#ngtools/webpack' },
{ test: /\.html$/, use: 'html-loader?minimize=false' },
{ test: /\.css$/, use: [ 'to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
]
},
plugins: [new CheckerPlugin()]
};
// Configuration for client-side bundle suitable for running in browsers
const clientBundleOutputDir = './wwwroot/dist';
const clientBundleConfig = merge(sharedConfig, {
entry: { 'main-client': './ClientApp/boot.browser.ts' },
output: { path: path.join(__dirname, clientBundleOutputDir) },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat(isDevBuild ? [
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
// Plugins that apply in production builds only
new webpack.optimize.UglifyJsPlugin(),
new AngularCompilerPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'),
exclude: ['./**/*.server.ts']
})
])
});
// Configuration for server-side (prerendering) bundle suitable for running in Node
const serverBundleConfig = merge(sharedConfig, {
resolve: { mainFields: ['main'] },
entry: { 'main-server': './ClientApp/boot.server.ts' },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./ClientApp/dist/vendor-manifest.json'),
sourceType: 'commonjs2',
name: './vendor'
})
].concat(isDevBuild ? [] : [
// Plugins that apply in production builds only
new AngularCompilerPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.module.server#AppModule'),
exclude: ['./**/*.browser.ts']
})
]),
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, './ClientApp/dist')
},
target: 'node',
devtool: 'inline-source-map'
});
return [clientBundleConfig, serverBundleConfig];
};
When i now start the application (performing npm install, then run webpack with --env.prod switch) with Release-config out of VS2017 i get the stacktrace above. The same thing happens when i deploy the application to Azure.
On localhost if i wait a few seconds and force-reload my browser, the application suddenly works. This does not work on Azure, which is kinda strange to me.
Do you have any suggestions what i might have done wrong or what i am missing?
I had the same issues for few days, I found a VS2017 - Angular 5 project in GitHub (don't have the exact URL), from which I have copied the webpack.config.js
I have also updated my Angular to 5.0.3
I than ran the 'dotnet publish' which worked (or 'dotnet publish -c Release')
The only problem I faced (and still facing) is during the complication, the compiler messes up the main-server.js, so as a workaround I have copied the main-server.js before the complication (10MB vs 2MB).
When running 'dotnet mydll.dll' - works great.
The webpack.config.js:
/*
* Webpack (JavaScriptServices) with a few changes & updates
* - This is to keep us inline with JSServices, and help those using that template to add things from this one
*
* Things updated or changed:
* module -> rules []
* .ts$ test : Added 'angular2-router-loader' for lazy-loading in development
* added ...sharedModuleRules (for scss & font-awesome loaders)
*/
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const AngularCompilerPlugin = require('#ngtools/webpack').AngularCompilerPlugin;
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
//const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = (env) => {
// Configuration in common to both client-side and server-side bundles
const isDevBuild = !(env && env.prod);
const sharedConfig = {
stats: { modules: false },
context: __dirname,
resolve: { extensions: ['.js', '.ts'] },
output: {
filename: '[name].js',
publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
module: {
rules: [
{ test: /\.ts$/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader', 'angular2-router-loader'] : '#ngtools/webpack' },
{ test: /\.html$/, use: 'html-loader?minimize=false' },
{ test: /\.css$/, use: ['to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize'] },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' } ]
},
plugins: [new CheckerPlugin()]
};
// Configuration for client-side bundle suitable for running in browsers
const clientBundleOutputDir = './wwwroot/dist';
const clientBundleConfig = merge(sharedConfig, {
entry: { 'main-client': './ClientApp/boot.browser.ts' },
output: { path: path.join(__dirname, clientBundleOutputDir) },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat(isDevBuild ? [
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
// new BundleAnalyzerPlugin(),
// Plugins that apply in production builds only
new webpack.optimize.UglifyJsPlugin(),
new AngularCompilerPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'),
exclude: ['./**/*.server.ts']
})
]),
devtool: isDevBuild ? 'cheap-eval-source-map' : false,
node: {
fs: "empty"
}
});
// Configuration for server-side (prerendering) bundle suitable for running in Node
const serverBundleConfig = merge(sharedConfig, {
// resolve: { mainFields: ['main'] },
entry: { 'main-server': './ClientApp/boot.server.ts' },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./ClientApp/dist/vendor-manifest.json'),
sourceType: 'commonjs2',
name: './vendor'
}),
new webpack.ContextReplacementPlugin(
// fixes WARNING Critical dependency: the request of a dependency is an expression
/(.+)?angular(\\|\/)core(.+)?/,
path.join(__dirname, 'src'), // location of your src
{} // a map of your routes
),
new webpack.ContextReplacementPlugin(
// fixes WARNING Critical dependency: the request of a dependency is an expression
/(.+)?express(\\|\/)(.+)?/,
path.join(__dirname, 'src'),
{}
)
].concat(isDevBuild ? [] : [
new webpack.optimize.UglifyJsPlugin({
compress: false,
mangle: false
}),
// Plugins that apply in production builds only
new AngularCompilerPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.module.server#AppModule'),
exclude: ['./**/*.browser.ts']
})
]),
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, './ClientApp/dist')
},
target: 'node',
// switch to "inline-source-map" if you want to debug the TS during SSR
devtool: isDevBuild ? 'cheap-eval-source-map' : false
});
return [clientBundleConfig, serverBundleConfig];
};
EDIT -
In addition to the changes on the webpack.config.js, I did the following two changes which solved my problem!:
In index.cshtml:
change from
<app asp-prerender-module="ClientApp/dist/main-server">Loading...</app>
to:
<app>Loading...</app>
In boot.server.ts:
change from:
const zone = moduleRef.injector.get(NgZone);
to:
const zone: NgZone = moduleRef.injector.get(NgZone);
Read http://www.talkingdotnet.com/upgrade-angular-4-app-angular-5-visual-studio-2017/ for more info.

Resources