Typescript compiles with warnings - javascript

I am restructuring the app and switching to monorepo using CRA and refactoring existing CRA configs.
The folder structure now looks like this.
.
├── api
│ ├── business
│ └── consumer
└── tsconfig.json
├── apps
│ ├── business
└── tsconfig.json
│ │ └── src
│ │ ├── components
│ │ ├── constants
│ │ ├── pages
│ │ └── reducers
│ └── consumer
└── tsconfig.json
│ └── src
│ ├── components
│ ├── constants
│ ├── pages
│ ├── reducers
│ └── selectors
├── config
│ ├── jest
│ └── utils
├── core
│ ├── components
│ ├── helpers
│ ├── services
│ ├── static
│ │ ├── images
│ │ └── styles
│ └── utils
├── public
├── scripts
├── tsconfig.json
├── shared
│ ├── components
│ ├── constants
│ ├── hooks
│ ├── redux
│ ├── selectors
│ └── types
I have added root paths in the root tsconfig.json and extended it for every in-module tsconfig.json.The root tsconfig.json looks like this
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"core/*": [
"core/*"
],
"api/*": [
"api/*"
],
"apps/*": [
"apps/*"
],
"shared/*": [
"shared/*"
],
"types/*": [
"shared/types/*"
],
"styles/*": [
"core/static/styles/*"
],
},
"jsx": "preserve",
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"noEmit": true,
"strict": true,
"allowJs": true,
"sourceMap": true,
"skipLibCheck": true,
"noImplicitAny": false,
"esModuleInterop": true,
"resolveJsonModule": true,
"noFallthroughCasesInSwitch": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"incremental": true,
"tsBuildInfoFile": "./buildcache/front-end",
},
"exclude": ["node_modules", "**/*.js"]
}
And here is the tsconfig.json for the business app.
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"components/*": [
"src/components/*"
],
"constants/*": [
"src/constants/*"
],
"helpers/*": [
"src/helpers/*"
],
"pages/*": [
"src/pages/*"
],
"reducers/*": [
"src/reducers/*"
],
"selectors/*": [
"src/selectors/*"
],
"types/*": [
"src/types/*"
],
"core/*": [
"../../core/*"
],
"apps/*": [
"../../apps/*"
],
"shared/*": [
"../../shared/*"
],
"api/*": [
"../../api/*"
]
}
},
"extends": "../../tsconfig.json"
}
I have also refactored paths.js to match my current folder structure ( P.S. - CRA doesn't allow to import files outside of the src so I changed paths ).
appName can be either business or consumer.I am running the app like npm start business which exposes the app name to the node process.
const grpConfig = require('./grp-config');
const parseArgv = require('./utils/parse-argv');
const args = parseArgv(process.argv);
const devMode = process.env.NODE_ENV === 'dev' || process.env.NODE_ENV === 'development';
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
const publicUrlOrPath = devMode ? '/' : `${grpConfig.CDN_URL}/${args.appName}/`;
const moduleFileExtensions = [
'web.mjs',
'mjs',
'web.js',
'js',
'web.ts',
'ts',
'web.tsx',
'tsx',
'json',
'web.jsx',
'jsx',
];
// Resolve file paths in the same order as webpack
const resolveModule = (resolveFn, filePath) => {
const extension = moduleFileExtensions.find(extension =>
fs.existsSync(resolveFn(`${filePath}.${extension}`)),
);
if (extension) {
return resolveFn(`${filePath}.${extension}`);
}
return resolveFn(`${filePath}.js`);
};
// config after eject: we're in ./config/
module.exports = {
publicUrlOrPath,
appRoot: resolveApp('.'),
appSrc: resolveApp(`${args.appName}/src`),
appPath: resolveApp(`apps/${args.appName}`),
dotenv: resolveApp('.env'),
appPublic: resolveApp('public'),
yarnLockFile: resolveApp('yarn.lock'),
appHtml: resolveApp(`public/index.html`),
appTsConfig: resolveApp(`apps/${args.appName}/tsconfig.json`),
appJsConfig: resolveApp('jsconfig.json'),
appPackageJson: resolveApp('package.json'),
appNodeModules: resolveApp('node_modules'),
appBuild: resolveApp(`build/${args.appName}`),
appWebpackCache: resolveApp('node_modules/.cache'),
swSrc: resolveModule(resolveApp, 'src/service-worker'),
testsSetup: resolveModule(resolveApp, 'tests/setupTests'),
appIndexJs: resolveModule(resolveApp, `apps/${args.appName}/index`),
appTsBuildInfoFile: resolveApp('node_modules/.cache/tsconfig.tsbuildinfo'),
};
module.exports.moduleFileExtensions = moduleFileExtensions;
And finally the webpack config.
{
// Webpack noise constrained to errors and warnings
mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
// Stop compilation early in production
bail: isEnvProduction,
devtool: isEnvProduction
? shouldUseSourceMap
? 'source-map'
: false
: isEnvDevelopment && 'cheap-module-source-map',
// These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle.
entry: paths.appIndexJs,
output: {
// The build folder.
path: paths.appBuild,
pathinfo: isEnvDevelopment,
filename: isEnvProduction
? 'static/js/[name].[contenthash:8].js'
: isEnvDevelopment && 'static/js/bundle.js',
chunkFilename: isEnvProduction
? 'static/js/[name].[contenthash:8].chunk.js'
: isEnvDevelopment && 'static/js/[name].chunk.js',
assetModuleFilename: 'static/media/[name].[hash][ext]',
publicPath: paths.publicUrlOrPath,
devtoolModuleFilenameTemplate: isEnvProduction
? info =>
path
.relative(paths.appSrc, info.absoluteResourcePath)
.replace(/\\/g, '/')
: isEnvDevelopment &&
(info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
},
resolve: {
alias: {
// api: path.resolve(__dirname, 'api'),
// apps: path.resolve(__dirname, 'apps'),
// core: path.resolve(__dirname, 'core'),
// shared: path.resolve(__dirname, 'shared'),
components: path.resolve(__dirname, 'apps', 'business', 'src', 'components'),
reducers: path.resolve(__dirname, 'apps', 'business', 'src', 'components'),
// reducers: path.resolve(__dirname, paths.appPath, 'src', 'reducers'),
// pages: path.resolve(__dirname, 'apps', 'business', 'src', 'pages'),
// constants: path.resolve(__dirname, 'apps', 'business', 'src', 'constants'),
// helpers: path.resolve(__dirname, 'apps', 'business', 'src', 'helpers'),
// selectors: path.resolve(__dirname, 'apps', 'business', 'src', 'selectors'),
// types: path.resolve(__dirname, 'apps', 'business', 'src', 'types'),
},
},
module: {
strictExportPresence: true,
},
plugins: [
new ModuleNotFoundPlugin(paths.appPath),
// TypeScript type checking
useTypeScript &&
new ForkTsCheckerWebpackPlugin({
async: isEnvDevelopment,
typescript: {
typescriptPath: resolve.sync('typescript', {
basedir: paths.appNodeModules,
}),
configFile: paths.appTsConfig,
context: paths.appPath,
diagnosticOptions: {
syntactic: true,
},
mode: 'write-references',
// profile: true,
},
logger: {
infrastructure: 'silent',
},
}),
].filter(Boolean),
// Turn off performance processing because we utilize
// our own hints via the FileSizeReporter
performance: false,
}
I have removed nonrelated webpack configs so as not to create a mess for your convenience.
I am not sure what I have set up wrong, but when I am running npm start business, it throws me a lot of warnings like this.
Cannot find module 'reducers/root-reducer' or its corresponding type
declarations.
import { rootReducer } from 'reducers/root-reducer';

Related

Webpack config to generate bundles of two different React SPAs

I have a project with the following structure:
.
├── app
│   ├── icon.svg
│   ├── index.html
│   └── scripts
├── config
│   └── iparams.json
├── jest.config.js
├── manifest.json
├── __mocks__
│   └── svgrMock.js
├── package.json
├── public
│   ├── index.html
│   └── iparams.html
├── setUpTests.js
├── src
│   ├── App.css
│   ├── app.index.css
│   ├── app.index.js
│   ├── App.js
│   ├── App.test.js
│   ├── assets
│   ├── components
│   ├── Config.css
│   ├── config.index.css
│   ├── config.index.js
│   ├── Config.js
│   ├── hooks
│   ├── log
│   └── logo.svg
├── webpack.config.js
└── yarn.lock
It have two main SPAs: config and app, so, I need to generate two different bundles respectively to ./config and ./app using webpack. The ./src/config.index.js is the entry point of the config app, witch renders the ./src/Config.js React component to the ./config/iparams.html page (using the ./public/iparams.html template). The same logic holds for the app page.
Currently I'm using this webpack config without success:
'use strict';
const HtmlWebPackPlugin = require('html-webpack-plugin');
const {
CleanWebpackPlugin
} = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
entry: {
'../app/': ['#babel/polyfill', `${process.cwd()}/src/app.index.js`],
'../config/': ['#babel/polyfill', `${process.cwd()}/src/config.index.js`]
},
output: {
globalObject: 'this',
path: `${process.cwd()}/dist`,
filename: '[name].[contenthash:8].js',
chunkFilename: '[name].[contenthash:8].js',
publicPath: './scripts',
clean: true
},
devtool: 'source-map',
module: {
rules: [{
test: /\.(js|jsx|ts|tsx|test.js)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.(css|scss)$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|jpe?g|gif|svg)$/i,
use: [{
loader: 'file-loader',
options: {
name: '[name][contenthash:8].[ext]',
outputPath: '/assets/img',
esModule: false
}
}]
},
{
test: /\.html$/,
use: [{
loader: 'html-loader'
}]
}
]
},
plugins: [
new CleanWebpackPlugin({
dangerouslyAllowCleanPatternsOutsideProject: true,
dry: false
}),
new MiniCssExtractPlugin({
filename: '[name].[contenthash:8].css',
chunkFilename: '[name].[contenthash:8].css'
}),
new HtmlWebPackPlugin({
template: `${process.cwd()}/public/index.html`,
filename: `${process.cwd()}/app/index.html`
}),
new HtmlWebPackPlugin({
template: `${process.cwd()}/public/iparams.html`,
filename: `${process.cwd()}/config/iparams.html`
}),
new CopyWebpackPlugin([
{
from: 'dist/**/*',
to: '../app'
}
]),
],
optimization: {
moduleIds: 'deterministic',
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: -10,
chunks: 'all'
}
}
}
}
};
What is the correct webpack configuration for this use case? Note that I'm using a proprietary sdk which doesn't allow a custom build script, just a custom webpack config, also, the pages outputs must be ./app and ./config.

Webpack: include html files and their js scripts alongside standalone js scripts

I current have a project that follows this structure:
src/
├── browserAction/
│ ├── assets/
│ ├── index.html
│ ├── script.js
│ └── style.css
├── options/
│ ├── assets/
│ ├── index.html
│ ├── script.js
│ └── style.css
├── manifest.json
├── background_script.js
└── content_script.js
I currently have webpack setup to transpile the background and content script with babel and copy the manifest as a standalone file but I can't figure out how to bundle the two index.html files (containing the contents of script.js and style.js) and keep the file structure of being in two separate folders. My current webpack config is:
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const IS_PRODUCTION = process.env.NODE_ENV === 'production';
module.exports = {
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
},
context: path.resolve(__dirname, 'src'),
entry: { background_script: './background_script.js', content_script: './content_script.js'},
module: {
rules: [
{
test: /\.html$/i,
use: [
'file-loader',
'extract-loader',
{
loader: 'html-loader',
options: {
minimize: IS_PRODUCTION,
},
},
],
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.m?js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env'],
},
},
],
},
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
},
},
],
},
],
},
plugins: [new CopyWebpackPlugin({ patterns: [{ from: 'manifest.json', to: '.' }] }), new CleanWebpackPlugin()],
};
And my intent is the output into dist matches:
dist/
├── browserAction/
│ └── index.html
├── options/
│ └── index.html
├── manifest.json
├── background_script.js
└── content_script.js
What loaders do I need to use to achieve this? I've been experimenting with various ones but I can't get the results I need.
You're looking for html-webpack-plugin. An example configuration:
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
context: path.resolve(__dirname, 'src'),
entry: {
browser_action: './browserAction/script.js',
options: './options/script.js',
background_script: './background_script.js',
content_script: './content_script.js'
},
module: {
// your loaders
// ...
},
plugins: [
new HtmlWebpackPlugin({
filename: 'browserAction/index.html',
template: 'browserAction/index.html',
chunks: ['browser_action']
}),
new HtmlWebpackPlugin({
filename: 'options/index.html',
template: 'options/index.html',
chunks: ['options']
})
]
}
By the way, it looks like you're trying to write a browser extension; I'd recommend a boilerplate like this which has webpack already configured.

Get a path to a file from Node application

I have an application, where structure looks like this:
.
├── index.js
├── unix
│   ├── index.js
└── win32
├── foo.exe
└── index.js
win32/index.js was accessing foo.exe like this:
let command = path.join(__dirname, "foo.exe") + ' -some-arguments';
exec(command);
But now using Webpack I compile my application into one bundle.js and put that foo.exe next to it:
.
├── foo.exe
└── bundle.js
And now path.join(__dirname, "foo.exe") doesn't work anymore. It doesn't find the foo.exe. I've changed it to
let command = path.resolve(
"node_modules/my-library/dist",
"foo.exe"
);
And it works fine but looks like there is a better way to do it.
UPD:
my Webpack config file:
const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
mode: "production",
entry: "./src",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
libraryTarget: "umd"
},
plugins: [new CopyPlugin([{ from: "./src/win32/foo.exe" }])],
target: "node"
};
To have __dirname behave the usual way, and not being it changed (mocked) by Webpack, you have to add a property in your Webpack config :
module.exports = {
//...
node: {
__dirname: false,
}
};
Documentation
You need to add these node config in your webpack. So you can use __dirname after you built your code with webpack
node: {
__dirname: false,
},

How to use Webpack to bundle all imported dependencies in a single file?

I have the following directory structure...
root
│ package.json
│ webpack-client.config.js
│ webpack-server.config.js
│ yarn.lock
├───assets
│ └───js
│ index.js
├───dist
│ │ header.html
│ │ hotel-details.html
│ │ hotel-list.html
│ │ index.html
│ │ server.js
│ │
│ └───static
│ └───j
│ index.js
├───node_modules
│ └...
├───server
│ database.js
│ index.js
└───views
header.html
hotel-details.html
hotel-list.html
index.html
I want to use Webpack for two things.
minify and bundle server side JS - export the bundle to dist/server.js using server/index.js as the entry point. I have achieved this using the webpack-server.config.js provided below.
minify each views/*.html file and export it to dist/v/*.html. If the html files have <script> tags I want to create minified bundles from those files and export them to dist/static/j/[html_filename].js.
I'm struggling with this one. I managed to minify the .html file and export it's .js files to dist/static/j/[html_filename].js. However, I can't use the .js file from html as it uses syntax like require or import. I've provided the content of both assets/js/index.js and dist/static/j/index.js.
webpack-client.config.js
var path = require("path");
var fs = require("fs");
var htmlFiles = {};
fs.readdirSync(path.join(__dirname, 'views'))
.filter(f => (path.parse(f).ext.toLowerCase() === '.html'))
.forEach(f => {
var name = path.parse(f).name;
htmlFiles[name] = path.join(__dirname, 'views', f);
});
module.exports = {
module: {
rules: [
{
test: /\.html$/,
use: [
{ loader: 'file-loader', options: { name: '[name].[ext]', emitFile: true }},
{ loader: 'extract-loader' },
{
loader: 'html-loader',
options: {
minimize: true,
attrs: ['script:src']
}
},
]
},
{
test: /\.js$/,
use: [
{
loader: 'file-loader',
options: {
name: 'static/j/[name].[ext]',
publicPath: (p) => p.replace('static/', '')
}
},
{
loader: 'babel-loader',
options: {
presets: [
[
"babel-preset-env", {
"targets": {
"chrome": 52
}
}
]
]
}
},
]
}
]
},
target: 'web',
watch: true,
entry: htmlFiles,
output: {
path: path.join(__dirname, "dist"),
filename: '[name].html.js'
}
};
webpack-server.config.js
var path = require("path");
var fs = require("fs");
const MinifyPlugin = require('babel-minify-webpack-plugin');
var nodeLibs = {};
fs.readdirSync(path.join(__dirname, 'node_modules'))
.filter(x => x !== '.bin')
.forEach(mod => { nodeLibs[mod] = 'commonjs ' + mod; });
module.exports = {
externals: nodeLibs,
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['babel-preset-env']
}
}
}
]
},
plugins: [
new MinifyPlugin()
],
context: __dirname,
entry: {
server: "./server/index.js"
},
target: "node",
output: {
path: path.join(__dirname, "dist"),
filename: "server.js"
}
};
assets/js/index.js
import $ from '../../node_modules/jquery';
let scrollEnabled = true;
window.setScrollEnabled = (scrollEnabled) => {
$('body').css({backgroundColor: 'red'});
console.log('isScrollEnabled:', scrollEnabled);
}
You want to use a JS file as you entry point, not HTML. The documentation for entry points might be useful.

Webpack font not found

I started learning webpack and I have this small project
I'll be simplifying the content for brevity, hopefully it wont affect your understanding of the problem.
.
└── project
├── dist
│   ├── fonts
│   └── js
├── src
│   ├── app
│ │ ├── app.js
│ │ └── component
│ │ ├── component.css
│ │ ├── component.directive.js
│ │ └── component.html
│   └── fontello
├── index.html
├── package.json
└── webpack.config.js
I'm trying to keep everything inside my component encapsulated so I have:
component.directive.js
require('../../fontello/css/fontello.css');
require('./component.css');
var angular = require('angular');
...
module.exports = angular.module('directives.component', [])
.directive('component', component)
.name;
app.js
var angular = require('angular');
var component = require('./component/component.directive.js');
...
angular.module('app', [component])
and webpack.config.js
var webpack = require('webpack');
module.exports = {
context: __dirname + '/src',
entry: {
app: './app/app.js',
vendor: ['angular']
},
output: {
path: __dirname + '/dist',
filename: 'js/app.bundle.js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin("vendor", "js/vendor.bundle.js")
],
module: {
loaders: [{
test: /\.css$/,
loader: 'style-loader!css-loader',
exclude: ['./src/fontello']
}, {
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)(\?[a-z0-9=&.]+)?$/,
loader: 'file-loader?name=fonts/[name].[ext]'
}, {
test: /\.html$/,
loader: 'raw'
}]
}
};
and I get for woff2/woff/ttf
404 Not Found. GET http://localhost:8080/fonts/fontello.woff2
what am I doing wrong?

Categories