Karma not recognizing Angular2 modules and components with Rails Webpacker - ruby-on-rails

My team updated the Rails version of our application to 5.1 so we could use Webpacker, a wrapper to use Webpack with Rails and then use Angular 2 properly.
We started setting up the test suite for the Angular 2 modules using Karma + Jasmine + Webpack following this article.
If I write simple test cases, without Angular Component, TestBed and ComponentFixture, everything looks fine. However, if I try to import Angular modules and test some components, Karma raises the following error message for every component and module:
ERROR in ./app/javascript/app/app.module.ts
Module parse failed: /[application path omitted]/app/javascript/app/app.module.ts Unexpected character '#' (17:0)
You may need an appropriate loader to handle this file type.
| import { AppRoutingModule } from './app-routing.module';
|
| #NgModule({
| imports: [
| BrowserModule,
The project structure is:
- app
-- ...
-- javascript (webpacker create this folder in the first time running)
---- app (where all modules are stored)
------ ...
------ app.routing.module.ts
------ app.component.ts
------ app.module.ts
------ echo.pipe.ts (a file created just to test the Karma suite)
---- packs
---- test
------ echo.pipe.spec.ts
------ main.js (entry point of tests)
------ main.spec.ts
The karma.conf.js file:
module.exports = function(config) {
config.set({
basePath: '',
frameworks: ['jasmine'],
files: [
{ pattern: './app/javascript/app/**/*.ts', watched: false, served: true },
{ pattern: './app/javascript/test/main.js', watched: false }
],
plugins: [
require('karma-webpack'),
require('karma-jasmine'),
require('karma-phantomjs-launcher'),
require('karma-chrome-launcher'),
require('karma-sourcemap-loader'),
require('karma-babel-preprocessor'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter')
],
exclude: [
],
preprocessors: {
'app/javascript/**/*.ts': ['webpack', 'sourcemap'],
'app/javascript/test/main.js': ['webpack', 'sourcemap']
},
mime: { 'text/x-typescript': ['ts','tsx'] },
reporters: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: false,
browsers: ['Chrome'],
singleRun: true,
concurrency: Infinity
})
}
The echo.pipe.ts file:
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'echo'
})
export class EchoPipe implements PipeTransform {
transform(value: any): any {
return value;
}
}
The main.js file:
describe('Meaningful Test', () => {
it('1 + 1 => 2', () => {
expect(1 + 1).toBe(2);
});
});
require('./main.spec.ts');
The main.spec.ts file:
import 'core-js/es6';
import 'core-js/es7/reflect';
import 'zone.js/dist/zone';
import 'zone.js/dist/proxy';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';
import 'zone.js/dist/jasmine-patch';
import 'rxjs/Rx';
import { TestBed } from '#angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting,
} from '#angular/platform-browser-dynamic/testing';
TestBed.initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
describe('Meaningful Test 2', () => {
it('1 + 1 => 2', () => {
expect(1 + 1).toBe(2);
});
});
The echo.pipe.spec.ts file:
import { Component } from '#angular/core';
import { TestBed, ComponentFixture, async } from '#angular/core/testing';
import { By } from '#angular/platform-browser';
import { DebugElement } from '#angular/core';
import { EchoPipe } from '../app/echo.pipe';
describe('EchoPipe', () => {
let comp: EchoPipe;
let fixture: ComponentFixture<EchoPipe>;
let de: DebugElement;
let el: HTMLElement;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ EchoPipe ],
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(EchoPipe);
comp = fixture.componentInstance;
comp.name = 'foo';
});
it('works well', () => {
fixture.detectChanges();
el = fixture.debugElement.nativeElement as HTMLElement;
expect(el.querySelector('p').textContent).toBe('foo');
});
});
const context = require.context('./', true, /\.spec\.ts$/);
context.keys().map(context);

Related

How to setup the middleware Service in nestJs application in nestjs-i18n package to get accept-language header without error?

Hey In my nestjs application, I have installed the nestjs-i18n npm package of version 10.2.6 . I have configured this I18nModule in the appModule as below :
app.module.ts :
import { MiddlewareConsumer, Module, NestModule } from '#nestjs/common';
import { ConfigModule } from '#nestjs/config';
import { PrismaModule } from './config/database';
import { SessionModule } from './modules/session/session.module';
import {
I18nModule,
QueryResolver,
AcceptLanguageResolver,
HeaderResolver,
} from 'nestjs-i18n';
import * as path from 'path';
import { I18nMiddleware } from './common/hooks/i18n/i18n.middleware';
#Module({
imports: [
PrismaModule,
SessionModule,
ConfigModule.forRoot({ isGlobal: true }),
I18nModule.forRoot({
fallbackLanguage: 'en',
fallbacks: {
'en-CA': 'fr',
'en-*': 'en',
'fr-*': 'fr',
pt: 'pt-BR',
},
loaderOptions: {
path: path.join(__dirname, '/i18n/'),
watch: true,
},
resolvers: [
{
use: QueryResolver,
options: ['lang'],
},
new HeaderResolver(['x-content-lang']),
AcceptLanguageResolver,
],
}),
],
controllers: [],
providers: [],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(I18nMiddleware).forRoutes('*');
}
}
I have also have the json files for multiple languages as below structure :
src Folder
|
|-i18n Folder
|
|--en Folder
|
|--en.json
| --fr Folder
|
| -- fr.json
| --etc
I have configured it in nest-cli.json as below :
nest-cli.json :
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "#nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": [
{
"include": "i18n/**/*",
"watchAssets":true
}
]
}
}
Problem :
I want to use the accept-language header to get the user-preferred language for translating the variables accordingly. So i have decided to implement the middleware to achieve it. But I don't know how to do it in the nestjs-i18n package .Please someone help me do this :
I hereby share the middleware i have written :
i18nMiddleware.ts :
import { Injectable, NestMiddleware } from '#nestjs/common';
import { FastifyRequest, FastifyReply } from 'fastify';
#Injectable()
export class I18nMiddleware implements NestMiddleware {
constructor() {}
async use(req: FastifyRequest, res: FastifyReply, next: () => void) {
const lang = req.headers['accept-language']?.toString();
console.log('............lang', lang);
if (lang) {
**// I want to what to write here to make the language received from the header**
}
next();
}
}
So please help me. Thanks in advance .

Vite multi-page app not working for the extra pages

I have a file structure like so app(main) and dashboard(secondary) being the different pages
but when trying to open the secondary app at /
vite.config.js
import * as path from "path";
import { defineConfig } from "vite";
import react from "vite-preset-react";
import svgr from 'vite-plugin-svgr'
import rollupReplace from "#rollup/plugin-replace";
const outDir = path.resolve(__dirname, 'build')
export default defineConfig({
plugins: [
rollupReplace({
preventAssignment: true,
values: {
__DEV__: JSON.stringify(true),
"process.env.NODE_ENV": JSON.stringify("development")
}
}),
react(),
svgr()
],
root: 'app',
build: {
root: outDir,
rollupOptions: {
input: {
app: path.resolve(__dirname, "app/index.html"),
dashboard: path.resolve(__dirname, "dashboard/index.html"),
}
}
},
});
and the server.js file is just an empty file not used

Import image with vanilla-extract and esbuild

I have a problem with images importing using vanilla-extract and esbuild
my build file:
const { build } = require("esbuild");
const { vanillaExtractPlugin } = require("#vanilla-extract/esbuild-plugin");
(async () => {
await build({
entryPoints: ["src/entry.tsx"],
bundle: true,
minify: true,
sourcemap: true,
platform: "browser",
outfile: "dist/entry.js",
plugins: [vanillaExtractPlugin()],
loader: {
".svg": "file",
},
});
})();
my entry.tsx
import { someStyle } from "./style.css";
console.log(someStyle);
When i importing my image in "css" way
import { style } from "#vanilla-extract/css";
export const someStyle = style({
backgroundColor: "url(./x.svg)",
});
The compiler return error
Could not resolve "./x.svg" (the plugin "vanilla-extract" didn't set a resolve directory)`
If i am trying to import x.svg using the typescript import
import { style } from "#vanilla-extract/css";
import svg from "./x.svg";
export const someStyle = style({
backgroundColor: `url(${svg})`,
});
I have other error
src/style.css.ts:5:16: error: No loader is configured for ".svg" files: src/x.svg'
Is it possible to import images with vanilla-extract modules without marking them as external?
It not working now. Workaround is to use babel
import babel from 'esbuild-plugin-babel';
plugins: [
babel({
filter: /.*.css.ts/,
config: {
presets: ['#babel/preset-typescript'],
plugins: ['#vanilla-extract/babel-plugin'],
},
}),
],

Webpacker, babel, uglifyjs-webpack-plugin - not transforming arrow functions, but only in Vue files

Running webpacker 3.5.5 (both the gem and package). This is mostly working, but in IE11 the app is broken because arrow functions do not appear to be transformed. However, inspecting the minified code it seems like the only place arrow functions aren't transformed are inside my vue components.
I think this is because my babel class properties plugin is not applying to my Vue loader somehow, but I haven't been able to come up with a solution.
Here's my .babelrc
{
"presets": [
[
"env",
{
"modules": false,
"targets": {
"browsers": [
"> 1%",
"IE 11"
],
"uglify": true
},
"useBuiltIns": true
}
]
],
"plugins": [
"syntax-dynamic-import",
"transform-object-rest-spread",
[
"transform-class-properties",
{
"spec": true
}
]
],
"env": {
"test": {
"presets": ["es2015"]
}
}
}
And here's the entirety of my environment.js file that modifies the webpack environment that webpacker ships with (vue loader is at the bottom).
const { environment } = require('#rails/webpacker');
environment.loaders.append('expose', {
test: require.resolve('jquery'),
use: [{
loader: 'expose-loader',
options: 'jQuery'
}]
});
const webpack = require('webpack');
// append some global plugins
environment.plugins.append('Provide', new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
axios: 'axios',
moment: 'moment-timezone',
_: 'lodash'
}));
// Necesary configuration for vue-loader v15
const VueLoaderPlugin = require('vue-loader/lib/plugin');
environment.plugins.append(
'VueLoaderPlugin',
new VueLoaderPlugin()
);
environment.loaders.append('vue', {
test: /\.vue$/,
loader: 'vue-loader'
});
module.exports = environment;
Edit for more info: Here is the entry point to my pack called 'wrestling'
import 'babel-polyfill';
import 'wrestling';
Then in wrestling.js...
import './styles/wrestling'
import Rails from 'rails-ujs'
Rails.start();
import wrestlingSetup from './wrestlingSetup'
wrestlingSetup();
WrestlingSetup contains the actual references to the vue files. I've cut down the file to show what a single vue import looks like within the file. All the rest are essentially the same.
import Vue from 'vue/dist/vue.esm'
// Redacted a bunch of imports, but they all look like this oen
import WrestlerCreate from './vue/wrestler_create.vue'
export default function() {
document.addEventListener('DOMContentLoaded', () => {
axiosSetup();
const app = new Vue({
el: '#app',
components: {
// Other vue components here that I've removed for simplicity
WrestlerCreate,
}
})
});
}
Here's an actual example of the Vue component
<template>
<div role="form">
<!-- other form elements -->
</div>
</template>
<script>
export default {
name: 'wrestler-create',
props: [
],
// This does not get transformed by babel
data() {
return {
loading: false,
error: false,
errorMessage: "Error, please try again later or contact support.",
first_name: '',
last_name: '',
weight_class: '',
academic_class: ''
}
},
methods: {
// removed for simplicity
}
}
</script>
For clarify sake:
Please use function() for data. I find function() gives me less trouble than arrow functions.
export default {
data: function() {
return {
message: "Hello something!",
secondMessage: "Hello world!"
};
}
}
If you really wish to use arrow function, you can write:
export default {
data: () => {
return {
message: "Hello something!",
secondMessage: "Hello world!"
};
}
}

how to import html files with webpack 2?

I can't figure out how to import html files with webpack 2! I am using angular 1.6.0 and typescript.
I would like to import a template and use it as a router state template:
import * as angular from 'angular';
import * as uiRouter from 'angular-ui-router';
import theView from './theView.html';
import appComp from './app.component';
export default angular
.module('app.main', [uiRouter])
.component('myAppComp', appComp)
.config(($stateProvider, $urlRouterProvider, $locationProvider) => {
'ngInject';
$locationProvider.hashPrefix('');
$stateProvider
.state('main', {
url: '/main',
template: '<p>main state template</p>'
})
.state('main.cardList', {
url: '/cardList',
template: theView
});
}
It gives:
error:
ERROR in ./src/app/module.ts
(3,22): error TS2307: Cannot find module './theView.html'.
What (wierd) I don't understand is if I import the template same as above and use it in a component template, it does gives same error "cannot find module './theView.html'" but it works!
This works (with ts compilation error):
import template from './theView.html';
.component(appComp, {
template
})
webpack.config:
module.exports = {
entry: './src/app/module.ts',
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.html$/,
use: [{ loader: 'html-loader' }]
}
]
},
output: {
filename: 'bundle.js',
path: __dirname + "/dist"
}
};
What is going on here..?
For the people who can come across this problem in the future; it is solved as follows:
declare const require: any;
$stateProvider
.state('main.cardList', {
url: '/cardList',
template: require('./theView.html').default
});
Credits to #yadejo for the answer above!

Resources