Webpack doesn't process TypeScript-based node_modules - ruby-on-rails

I stuck for a while about importing .ts or .tsx files from the node_modules folder into the app. It turns out babel is unable to process typescript-based things from there.
Here is an example:
ERROR in ./node_modules/#ui-kit/components/Link/index.tsx 32:1
Module parse failed: Unexpected token (32:1)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| arrowName = 'down',
| linkColor
> }: IProps) => {
| const _handleClick = (e) => {
| onClick && onClick(e);
# ./node_modules/src/index.ts 10:0-37 25:0-44:2
Here is my loader for TS|TSX:
{
test: /\.(js|jsx|ts|tsx)?$/,
exclude: [/node_modules\/(?!(#ui-kit)\/).*/],
use: [
{
loader: 'ts-loader',
options: {
allowTsInNodeModules: true,
compilerOptions: {
target: __DEV__ ? 'ES2019' : 'ES5'
}
}
}
]
}

Let's open the environmet.js file. Then, remove general loaders:
// ------------------------------------
// Loaders
// ------------------------------------
environment.loaders.delete('file')
environment.loaders.delete('babel')
environment.loaders.delete('nodeModules')
Add your own by config option:
// ------------------------------------
// Loaders
// ------------------------------------
environment.config.module = {
...environment.config.module,
rules: [
{
test: /\.(js|jsx|ts|tsx)?$/,
exclude: [/node_modules\/(?!(#ui-kit)\/).*/],
use: [
{
loader: 'ts-loader',
options: {
allowTsInNodeModules: true,
compilerOptions: {
target: 'ES2019'
}
}
}
]
},
{
type: 'javascript/auto',
test: /\.json$/,
use: ['json-loader']
},
// FILE/IMAGES
{
test: /\.woff(\?.*)?$/,
use: ['url-loader?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=application/font-woff']
},
{
test: /\.woff2(\?.*)?$/,
use: ['url-loader?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=application/font-woff2']
},
{
test: /\.otf(\?.*)?$/,
use: ['file-loader?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=font/opentype']
},
{
test: /\.ttf(\?.*)?$/,
use: ['url-loader?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=application/octet-stream']
},
{
test: /\.eot(\?.*)?$/,
use: ['file-loader?prefix=fonts/&name=[path][name].[ext]']
},
{
test: /\.svg(\?.*)?$/,
use: ['url-loader?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=image/svg+xml']
},
{
test: /\.(png|jpg)$/,
use: ['url-loader?limit=8192']
}
]
}

Related

esbuild How to build a product without a filesystem

I want esbuild to automatically handle the duplicate imports in the file for me, and I also want to use its tree shaking capabilities to help me optimise my code and then output it to a file, I wrote the following code to try and do the above, but I could never get it right
export interface ConfigSource extends Partial<Options> {
code: string
name: string
loader: Loader
}
export interface Config {
sources: ConfigSource[]
options?: BuildOptions
}
function babelBuildWithBundle(main: ConfigSource, config: Config) {
const buildModuleRuntime: Plugin = {
name: 'buildModuleRuntime',
setup(build) {
build.onResolve({ filter: /\.\// }, (args) => {
return { path: args.path, namespace: 'localModule' }
})
build.onLoad({ filter: /\.\//, namespace: 'localModule' }, (args) => {
const source = config.sources.find(
(source) =>
source.name.replace(/\..+$/, '') === args.path.replace(/^\.\//, '')
)
const content = source?.code || ''
return {
contents: content,
loader: source?.loader || 'js',
}
})
},
}
return build(
{
stdin: {
contents: main.code,
loader: main.loader,
sourcefile: main.name,
resolveDir: path.resolve('.'),
},
bundle: true,
write: false,
format: 'esm',
outdir: 'dist',
plugins: [buildModuleRuntime],
}
)
}
const foo = `
export const Foo = FC(() => {
return <div>gyron</div>
})
`
const app = `
import { Foo } from './foo'
function App(): any {
console.log(B)
return <Foo />
}
`
const bundle = await babelBuildWithBundle(
{
loader: 'tsx',
code: app,
name: 'app.tsx',
},
{
sources: [
{
loader: 'tsx',
code: foo,
name: 'foo.tsx',
},
],
}
)
Then the only answer I got in the final output was
console.log(bundle.outputFiles[0].text)
`
// localModule:. /foo
var Foo = FC(() => {
return /* #__PURE__ */ React.createElement("div", null, "gyron");
});
`
console.log(bundle.outputFiles[1])
`
undefined
`
I have just tried setting treeShaking to false and can pack the app into the product.

Webpack-4 CSS-Loader error unknown word at module.export

I'm new at webpack and have been trying to implement it for a legacy site. No matter how many solutions I try I always get 'Unknown word' error on build using sass/raw/css/loaders. The error seems to happen at 'module.export' which is, I guess, added as a result of importing a style sheet in .js file. Here is my webpack.config.js:
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: { presets: ["env"] }
}
},
{ // sass / scss loader for webpack
test: /\.(sass|scss)$/,
use: [
'css-loader',
'raw-loader',
'sass-loader'
],
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
use: [ 'file-loader' ]
}
]
}
In index.js:
`import '../css/global.scss';`
The global.scss file consists of a list of #import statements.
Here is the error I get:
ERROR in ./css/analytics/global.scss
Module build failed: Unknown word (1:1)
> 1 | module.exports = ".custom {\n (...)
It seems that no matter what is on the global.scss file, the appended 'module.exports' appears to break the build.
I have tried many suggestions on the internet but none have worked.
Thanks in advance!
I figured out what I was doing wrong. The raw-loader wasn't the right loader for this situation, though it 'looked' like it had solved the issue of getting urls resolved. I replaced it with resolve-url-loader, plus a few more tweaks. Here is the result:
module: {
rules: [
{
test: /\.js$/,
use: {
loader: "babel-loader",
options: { presets: ["env"] }
}
},
{ // sass / scss loader for webpack
test: /\.(sass|scss)$/,
use: [
'style-loader',
'css-loader',
'resolve-url-loader',
'sass-loader?sourceMap'
],
},
{
test: /\.(jpg|png|gif)$/,
use: {
loader: "file-loader",
options: {
name: "[path][name].[hash].[ext]",
},
},
},
{
test: /\.svg$/,
use: "file-loader",
},
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: PATH_CONFIGS.global_path + '/fonts'
}
}]
}
]
So I am guessing the 'unknown word' error is a somewhat generic response that can point to many possible issues. Hope this helps someone who is in a similar situation.

Webpack error 'Error: Final loader didn't return a Buffer or String' when trying to compile React server side components using ReactJS.NET and MVC 5

I am getting the following error - 'Module build failed: Error: Final loader didn't return a Buffer or String' when trying to compile JSX components for server-side rendering using Webpack 2 and ReactJS.NET. I have followed the examples as described here as well as in this example.
My folder structure is similar to the Github example, I have one React component, an index.js file and a server.js file. Here are the contents:
/Content/components/TestComponent.jsx
var React = require('react');
class Test extends React.Component {
getInitialState() {
return { data: this.props.greeting };
}
render() {
return (
<div>
<h1>{this.props.greeting}</h1>
</div>);
}
}
module.exports = Test;
/Content/components/index.js
module.exports = {
Test: require('./TestComponent.jsx')
}
/Content/server.js
var Components = require('expose?Components!./components');
And here is my full webpack.config.js:
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: './Content/server',
output: {
path: __dirname + '/resources/dev/scripts/server',
filename: 'test.js'
},
module: {
rules: [
{
test: /\.js$|.jsx$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['env', 'react'],
}
}
{
test: require.resolve('react'),
loader: 'expose?React'
}
]
},
resolve: {
extensions: ['.js', '.jsx']
},
externals: {
react: 'React'
}
}
I have created an example project here with the same problem.
The solution was to do away with the /Content/server.js file, and instead use the expose-loader in webpack. Here is the updated webpack.config.js:
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: './Content/components/index',
output: {
path: __dirname + '/resources/dev/scripts/server',
filename: 'test.js'
},
module: {
rules: [
{
test: /\.js$|.jsx$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['env', 'react'],
}
},
{
test: require.resolve('./Content/components/index'),
use: [{
loader: 'expose-loader',
options: 'Components'
}]
},
{
test: require.resolve('react'),
use: [{
loader: 'expose-loader',
options: 'React'
}]
}
]
},
resolve: {
extensions: ['.js', '.jsx']
}
}

webpack: Inline css for a splash screen (above the fold css)

Im trying to figure out why a css segment will not run through 'style-ext-html-webpack-plugin'.
Currently I have a .CSS file with rules for the splash screen.
It's being extracted using 'extract-text-webpack-plugin' and injected to the template's <head> with 'extract-text-webpack-plugin'.
problem is, the file never gets run through 'style-ext-html-webpack-plugin' and I can't wrap my head around how to debug it.
(Ideally, I'd like to have a .SCSS file so it can be themeable through a .env file. i.e: have splash.scss exclusively extracted and inlined in the <head> after being injected with some theme colors)
webpack.config.js:
....
const ExtractTextPlugin = require('extract-text-webpack-plugin'); //used for above-the-fold css (such as splash-screen)
const StyleExtHtmlPlugin = require('style-ext-html-webpack-plugin');
const extractSplashCSS = new ExtractTextPlugin('splash.css');
module.exports = {
entry: {...},
output: {...},
resolve: {...},
plugins: [
...,
new HtmlWebpackPlugin({
title: enviroments.TITLE,
splashScreenTitle: enviroments.SPLASH_SCREEN_TITLE,
template: 'src/index.html',
cache: true,
favicon: enviroments.FAVICON || './src/assets/images/favicon.ico',
inject: 'body'
}),
extractSplashCSS,
new StyleExtHtmlPlugin('splash.css')
],
module: {
loaders: [
{ test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
{
test: /\.css$/,
loader: 'style-loader!css-loader!resolve-url-loader?import=false',
exclude: [path.join(path.resolve('./src'), 'common/app/splash.css')]
},
{
test: /\.css$/,
loader: extractSplashCSS.extract({
use: 'css-loader'
}),
include: [path.join(path.resolve('./src'), 'common/app/splash.css')]
},
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader?importLoaders=1',
{
loader: 'postcss-loader',
options: {
plugins: function() {
return [require('autoprefixer')];
}
}
},
'resolve-url-loader?sourceMap',
{
loader: 'sass-loader?sourceMap',
options: {
includePaths: path.resolve('./src'),
data: `
$color-primary: ${theme.PRIMARY};
....
`
}
}
]
},
....
]
}
};
index.js:
...
// above the fold css
import 'common/app/splash.css';
Needed to update html-webpack-plugin to 2.29.0.
I've managed to solve this issue, using a sass file that can be themeable with variables from .env file:
I had to explicitly exclude the splash file from the normal sass flow and create another loader definition explicitly for it:
...
const ExtractTextPlugin = require('extract-text-webpack-plugin'); //used for above-the-fold css (such as splash-screen)
const StyleExtHtmlWebpackPlugin = require('style-ext-html-webpack-plugin');
module.exports = {
...
plugins: [
...
new HtmlWebpackPlugin({
...
}),
new ExtractTextPlugin('splash.css'),
new StyleExtHtmlWebpackPlugin('splash.css'),
],
module: {
loaders: [
{ test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
{ test: /\.css$/, loader: 'style-loader!css-loader!resolve-url-loader?import=false' },
{
test: /\.scss$/,
exclude: [path.join(path.resolve('./src'), 'common/app/splash.scss')],
use: [
.....
]
},
{
test: /\.scss$/,
include: [path.join(path.resolve('./src'), 'common/app/splash.scss')],
use: ExtractTextPlugin.extract({
use: [
{
loader: 'css-loader',
options: {minimize: true}
},
{
loader: 'postcss-loader',
options: {
plugins: function() {
return [require('autoprefixer')];
}
}
},
{
loader: 'sass-loader',
options: { data: `$color-primary: ${theme.PRIMARY};` }
}
]
})
},
]
}
};

PostCSS CSSNext #media and color() not working with webpack 2

I'm upgrading a project from webpack 1 to 2, and am seeing some strange behavior with postcss-cssnext where some css next features, most notably color() functions and all my #media queries just aren't working anymore.
My webpack config with webpack 2 looks like this. What am I doing wrong here?
{
test: /\.css$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
localIndentName: 'localIdentName=[name]__[local]___[hash:base64:5]',
sourceMap: true,
modules: true,
importLoaders: 1
}
},
{
loader: 'postcss-loader',
options: {
plugins: [
postcssImport({ path: './app/css/common' }),
postcssCssnext({ browsers: ['> 1%', 'last 2 versions'] }),
postcssReporter({ clearMessages: true })
]
}
}
]
}
postcss-loader is probably responsible for this change (1.3.x).
According to doc, you should use a function for "plugins" option.
Or use an array but in a postcss.config.js file.
module.exports = {
module: {
rules: [
{
test: /\.css/,
use: [
…
{
loader: 'postcss-loader',
options: {
plugins: function () {
return [
postcssImport({ path: './app/css/common' }),
postcssCssnext({ browsers: ['> 1%', 'last 2 versions'] }),
postcssReporter({ clearMessages: true })
];
}
}
}
]
}
]
}
}
Or via postcss.config.js
module.exports = {
plugins: [
postcssImport({ path: './app/css/common' }),
postcssCssnext({ browsers: ['> 1%', 'last 2 versions'] }),
postcssReporter({ clearMessages: true })
]
}
(and in webpack)
module.exports = {
module: {
rules: [
{
test: /\.css/,
use: [
…
'postcss-loader',
]
}
]
}
}

Resources