Running ts-node scripts that import css modules - javascript

How can I run scripts that import css modules?
I'm writing a typescript migration script that I'd like to run via ts-node. Ideally, my codebase would be organized such that the script's dependencies never touch React components, but that's not the case. The script ultimately imports React components and thus css modules, so ts-node fails because it doesn't understand css modules:
RenderableInline.tsx(4,20): error TS2307: Cannot find module './styles/RenderableInline.module.scss' or its corresponding type declarations.
Only webpack understands how to build css modules, since I've configured it via a css-loader.
The only precedent for this I've found is jest, which has some configuration option for mocking out css modules so it can import these files without error: https://jestjs.io/docs/webpack.
How can I run a typescript script that has dependencies on css modules? Is there someway to do this via ts-node? Or does webpack have some script running feature?

Add a global .d.ts file that provides direction on how .css files should be handled.
Such as src/global.d.ts with the following contents:
declare module '*.module.css' {
const classes: { [key: string]: string };
export default classes;
}
May also be helpful to add the typescript-plugin-css-modules plugin. Note though that this only helps during development using VSCode but has no effect during compilation.
While I generally got this working, I am still facing problems to get this to work correctly with ts-node-dev - probably related to ts-node not loading these type files by default Missing Types. Unfortunately even using the --files directive, I couldn't get this to work.

Related

How to get typescript type completion for Pixi 6 native module?

I am building a PixiJS game with native ES modules, without using a bundler such as Parcel or Rollup.
I am also loading PixiJS as a native module, I found the module in node_modules/pixi.js/dist/esm/pixi.js. I can now use:
import { Sprite } from './pixi.mjs'
The only problem is that the accompanying index.d.ts file is not recognised by VS Code (I found this file in node_modules/pixi.js/index.d.ts), so type checking for PixiJS doesn't work correctly, even though the code DOES run!
My folder structure is super simple. There is not even a package.json.
index.html
js/app.js
js/pixi.mjs
js/pixi.mjs.map
js/index.d.ts
How can I force VS Code to read the index.d.ts file?
There are a couple of issues with this approach.
Declaration files are missing
First of all, if you look at the types installed by pixi.js in node_modules/pixi.js/index.d.ts you will find that it is mostly empty, and
it references external packages starting with #pixi. This is due to the mono-repo approach in the pixi project.
You will only fulfill those references if these packages are installed as npm modules (which happens automatically after installing pixi.js) and for which you need a package.json so that TypeScript finds them by their package name.
Link between imported classes and types
Secondly, VS Code (or better said, the TypeScript engine) is not capable of relating the files pixi.mjs and index.d.ts once they are moved out of the node_modules folder. Although the classes are named the same (Sprite, Container, etc.), TypeScript cannot safely conclude that they refer to the same thing.
This workflow is automatic when using npm thanks to the types property in node_modules/pixi.js/package.json. As an alternative, you can rename the file index.d.ts to pixi.mjs.d.ts and TypeScript will relate them by file name.
This is the folder structure that TypeScript can understand:
index.html
js/app.js
js/pixi.mjs
js/pixi.mjs.d.ts
js/pixi.mjs.map
TypeScript error detection in JS files
Finally, the previous fixes will only provide type inference but no error detection in js files. If you want VS Code to report errors, you need to create a tsconfig.json file with the following settings:
{
"compilerOptions": {
"noEmit": true,
"checkJs": true,
},
"include": ["js/*.js"],
}

How can I resolve the following compilation error when running Jest for testing?

Although I am able to start the npm project using npm start without any issues with webpack or babel, once I run npm test, I find the following error related to testing App.js using App.test.js (where App.js imports ApolloClient):
TypeError: Cannot assign to read only property '__esModule' of object '[object Object]'
| import ApolloClient from 'apollo-boost';
| ^
at node_modules/apollo-boost/lib/bundle.cjs.js:127:74
at Array.forEach (<anonymous>)
at Object.<anonymous> (node_modules/apollo-boost/lib/bundle.cjs.js:127:36)
Essentially, I'm confused as to why I get an error when running the test but not when starting the project.
I've tried adding in a number of babel plugins to both .babelrc and in my webpack config file:
#babel/plugin-transform-object-assign
#babel/plugin-transform-modules-commonjs
babel-plugin-transform-es2015-modules-commonjs
However, I haven't been able to resolve the issue. My thinking was that this is related to the fact that the file that fails to compile was originally CommonJS.
I was only able to find something relatively similar here, https://github.com/ReactTraining/react-router/pull/6758, but I didn't find a solution.
Is there something that I'm missing specifically related to running tests? I should also mention I've tried frameworks other than Jest and ran into the same issue.
EDIT:
I removed everything from App.test.js except the imports to isolate the issue so it just contains the following:
import React from 'react';
import { shallow } from 'enzyme/build';
import App from './App';
UPDATE:
I was able to resolve the initial error by upgrading apollo-boost from version 0.3.1 to 0.4.2. However, I now have a different error that is similarly frustrating. I am using Babel 7 and have added the plugin #babel/plugin-syntax-dynamic-import to both my .babelrc and to my webpack.config.js files. Despite this, I get the following error related to the use of a dynamic import in App.js when running the Jest to test App.test.js:
SyntaxError: Support for the experimental syntax 'dynamicImport' isn't currently enabled
Add #babel/plugin-syntax-dynamic-import (https://git.io/vb4Sv) to the 'plugins' section of your Babel config to enable parsing.
I'm not sure if there is a parsing error or something else, but I've tried numerous things that have not worked. The closest discussion I could find related to this problem is, https://github.com/facebook/jest/issues/5920, however, the proposed solutions don't work for me.
UPDATE:
One thing that I'm trying is to avoid duplication of the babel options as right now they're both in .babelrc and in the babel-loader options within webpack.config.js. From what I found online (Whats the difference when configuring webpack babel-loader vs configuring it within package.json?), the way to make webpack use the settings in .babelrc is to not specify options. However, doing so results in the same error described above showing up only this time when running npm start. I will add that the project that was originally created using create-react-app, however, in order to support multiple pages, I needed to customize webpack's configuration and so ejected from it. I'm not sure why this is so convoluted.
its probably a babel configuration issue, I'm pretty sure jest needs to be compiled to work with create-react-app...
did you specify a setup file in package.json:
"jest": {
"setupFiles": [
"/setupTests.js"
]
}
and in setupTests.js:
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
It turns out that one of the components in the project's src directory had its own local package.json file even though it wasn't being used and was not installed as a local dependency in the top level package.json (instead imports were done using relative urls). For some reason, the existence of this file changed the behavior of webpack and other tools when starting and testing the project such that none of the top level configurations were used for files within directories with separate package.json files. Once I removed these local package.json files from the components sub-directory, all the prior issues were resolved. One hallmark of this problem is that compilation errors were not showing up for JavaScript files that weren't nested under an alternate package.json file.
Hopefully this is useful for anyone that encounters similar errors as I don't think the cause can be directly determined from the compiler messages alone.

Load transpiled TS2 with HTML <script> tag?

I'm really new to Typescript2. I'm loving it and have written a module that I can easily import and use in other Typescript2 projects. But I also want my library to be able to be used as a standalone by simply using an HTML tag. When I do that, though, the browser complains "exports is undefined."
I'm guessing I have to write some sort of javascript that imports my module and instantiates it, and then have my browser load that wrapper script. Am I on the right track? How do I create a typescript that transpiles into something that I can just load natively in the browser with a script tag that just loads and instantiates?
You are on the right track. What you need is a module loader. For the browser, requirejs is mentioned in the typescript documentation, although there are several options (requirejs, browserify, webpack, rollup).
I use requirejs with typescript, so I have experience doing the following steps:
For requirejs, you could do the following to get started.
Ensure that you are compiling to modules in the AMD format when running the typescript compiler command (tsc) by using the typescript configuration file or command-line compiler option arguments
// tsconfig.json
{
"compilerOptions": {
"module": "amd"
}
}
Get requirejs
One source is http://requirejs.org/docs/download.html
Note the name of the .js file that is output by the typescript compiler
For example "my-script.js"
Add a script tag to the page
For example <script data-main="scripts/my-script" src="require.js"></script>
There is a simple "getting started" page for requirejs http://requirejs.org/docs/start.html
As a bonus, to export multiple modules to a single file, you can use the --outFile compiler option for typescript.

Webpack importing video.js returns an empty object

I am trying to use video.js via webpack.
I installed video.js via npm - npm install video.js --save-dev
In webpack I read that video.js should be loaded via script loader else it throws an error.
This is how I am loading video.js through the babel loader
module:
loaders: [
{
test: /video\.js/,
loader: 'script'
}
]
I got this solution from here https://github.com/videojs/video.js/issues/2750
This is my import statement
import videojs from 'video.js';
The issue that I now face is the import is returning an empty object, so when I try to do this:
var vidTag = ReactDOM.findDOMNode(this.refs.html5Video);
this.videojs = videojs(vidTag);
I get this error:
renderer-0.js:8031 Uncaught (in promise) TypeError: (0 , _video2.default) is not a function(…)
Any help will be much appreciated. I am new to ES6 / React / Webpack
Please take a look at the loader's README before copy&pasting some random code. The script-loader is not appropiate here, because it imports scripts into the global scope while skipping the whole module system.
So, if you wanted to use the script-loader, you would just write:
import "script-loader!video.js";
console.log(videojs); // should be an object now
Usually I would not recommend the use of the script-loader because it neglects the whole point of a module system where you import stuff explicitly into the local scope. In the example above, the import happens as a side-effect into the global scope which is effectively the same as just using a <script> tag with all its downsides like name clashes, etc.
There are often better alternatives to it, like the exports-loader, which appends a module.exports at the end of the module, thus turning an old-school global script into a CommonJS module.
In this particular case, however, you don't need a loader at all because video.js is already aware of a CommonJS module system. Just write import videojs from "video.js";.
There is another minor problem, however. If you compile this with webpack, it will print a warning to the console:
WARNING in ../~/video.js/dist/video.js
Critical dependencies:
13:480-487 This seems to be a pre-built javascript file. Though this is possible, it's not recommended. Try to require the original source to get better results.
# ../~/video.js/dist/video.js 13:480-487
This is because webpack detects that this file has already been bundled somehow. Often it's better to include the actual src with all its tiny modules instead of one large dist because this way webpack is able to optimize the bundle in a better way. I've written down an exhaustive explanation about how to import legacy scripts with webpack.
Unfortunately, video.js does not include its src in the version deployed at npm, so you're forced to use the dist. In order to get rid of the error message and to improve webpack's build time, you can instruct webpack to skip video.js when parsing the code for require() statements by setting the module.noParse option in your webpack.config.js:
module: {
noParse: [
/node_modules[\\/]video\.js/
]
}
Usually it's safe to flag all pre-bundled modules (typically those with a dist folder) as noParse because they are already self-contained.
include SDN
<script src="//vjs.zencdn.net/5.11/video.min.js"></script>
webpack config:
config.externals = {
'video.js': 'videojs'
};

JSPM : importing SCSS with SystemJS in Angular2/TypeScript project doesn't works

Context
I'm working on a project using Angular2, TS and SystemJS. I've built a simple module loader using SystemJS which allows me to import 'custom' modules like this :
import { NavComponent } from "component#nav";
Maybe it'll be important.
Goal
I would like to import .scss files inside my angular components to be able to do things like that :
#Component({
selector: 'app-view',
styles: [ require('path/to/mainScss/file.scss') ],
template: //...
})
Issue
I've found some examples using webpack but I can't get this works. During searching, I've found this module. It can be interesting because it uses SystemJS like me and I don't have to add webpack to my project.
So I've decided to use it (and I'm not sure if it's possible to use webpack and SystemJS at the same time. require was undefined). I didn't know jspm before using this module, I've always used npm. So I've installed jspm locally (relative to my project) and globally and I've installed the module.
Then, inside a component : import './styles/importer.scss!';. And I get an error here.
Error: SyntaxError: Unexpected token <. I know that this error happens when SystemJS failed to load a module but I can't figure out why.
Why ?!
Why am I trying to do that ?
My module loader allows me to write some modules in separate folders (named like this namepace#name). I can add those folders inside another one named modules/ and then enable/disable modules by editing a configuration file.
So I want my .scss files to be loaded only if a module is enabled. That's why I want to include my sass inside an Angular component. That way, it'll be loaded only if the component is loaded.

Categories