Webpack Pug/HTML loaders converts capital letters to lowercase on production mode - html

I am using both vue single-file components and separating of markup and logic to .pug and .ts files respectively. If you interesting why I don't unify is please see the comments section.
Problem
import template from "#UI_Framework/Components/Controls/InputFields/InputField.vue.pug";
import { Component, Vue } from "vue-property-decorator";
console.log(template);
#Component({
template,
components: {
CompoundControlBase
}
})
export default class InputField extends Vue {
// ...
}
In development building mode exported template is correct (I beautified it for readability):
<CompoundControlBase
:required="required"
:displayInputIsRequiredBadge="displayInputIsRequiredBadge"
<TextareaAutosize
v-if="multiline"
:value="value"
/><TextareaAutosize>
</CompoundControlBase>
In production mode, my markup has been lowercased. So, the console.log(template) outputs:
<compoundcontrolbase
:required=required
:displayinputisrequiredbadge=displayInputIsRequiredBadge
<textareaautosize
v-if=multiline
:value=value
></textareaautosize>
</compoundcontrolbase>
Off course, I got broken view.
Webpack config
const WebpackConfig = {
// ...
optimization: {
noEmitOnErrors: !isDevelopmentBuildingMode,
minimize: !isDevelopmentBuildingMode
},
module: {
rules: [
{
test: /\.vue$/u,
loader: "vue-loader"
},
{
test: /\.pug$/u,
oneOf: [
// for ".vue" files
{
resourceQuery: /^\?vue/u,
use: [ "pug-plain-loader" ]
},
// for ".pug" files
{
use: [ "html-loader", "pug-html-loader" ]
}
]
},
// ...
]
}
}
Comments
To be honest, I don't know why we need ? in resourceQuery: /^\?vue/u, (explanations are welcome).
However, in development building mode above config works property for both xxxx.vue and xxxx.vue.pug files.
I am using below files naming convention:
xxx.pug: pug file which will not be used as vue component template.
xxx.vue.pug: pug file which will be used as vue component template.
xxx.vue: single-file vue component.
xxx.vue.ts: the logic of vue component. Required exported template from xxx.vue.pug as in InputField case.
Why I need xxx.vue.ts? Because of this:
declare module "*.vue" {
import Vue from "vue";
export default Vue;
}
Neither public methods/fields nor non-default methods are visible for TypeScrpt xxx.vue files. For the common (non-applied) components, I can't accept it.
Repro
🌎 GitHub
Step 1: Install dependencies
npm i
Step 2: Let's check the development building first
npm run DevelopmentBuild
In line 156 of DevelopmentBuild\EntryPoint.js, you can check that below pug template:
Alpha
Bravo OK
has been compiled properly:
Step 3: Problem on production build
npm run ProuductionBuild
You can find the lowercased tags in the column 13:
You can also open index.html in your browser and check the console.log() output with compiled TestComponent.

The problem is the "html-loader". It has the option minimize set to true in production mode (html-loader/#minimize).
I had a similar problem in angular and had to unset some options like (see for reference html-minifier-terser#options-quick-reference).
// webpack.config.js
{
test: /\.pug$/u,
oneOf: [
// for ".vue" files
{
resourceQuery: /^\?vue/u,
use: [ "pug-plain-loader" ]
},
// for ".pug" files
{
use: [ "html-loader", "pug-html-loader" ]
}
],
options: {
minimize: { // <----
caseSensitive: false // <----
} // <----
}
},

Related

How do I limit the scope of `resolveJsonModule`?

I'm working on project that uses Typescript and webpack. I have to import json files, and I have to do it in two ways:
I have to import project's package.json as a module. This has already been implemented previously.
Have to import some json schemas as resources loadable by url. This is what I'm working on right now.
Using package.json (already implemented)
To import package.json, the tsconfig.json contains:
{
"compilerOptions": {
"resolveJsonModule": true,
"paths": {
"package.json": ["./package.json"]
}
},
}
And webpack config has:
/**
* Determine the array of extensions that should be used to resolve modules.
*/
resolve: {
extensions: [".js", ".ts", ".tsx", ".json"],
plugins: [
new TSConfigPathsPlugin({
configFile: path.join(__dirname, "../../tsconfig.json"),
logLevel: "info",
extensions: [".js", ".jsx", ".ts", ".tsx"],
mainFields: ["browser", "main"],
baseUrl: tsConfig.baseUrl,
}),
],
},
And this is how package.json is used:
import packageJson from "package.json";
//...
const release = `${packageJson.version}-${process.platform}`;
This is completely type-safe: ts checks that my package.json has version field. This is working as intended and I don't want to break it.
Using schema json files (what I'm implementing)
To add support for json schemas, I've added them with filenames matching .schema.json$ and have added this to webpack config:
module: {
rules: [
{
test: /\.schema.json$/,
type: "asset/resource",
},
],
},
And this to a global type declaration file:
declare module "*.schema.json" {
declare const uri: string;
export default uri;
}
I thought that by doing that, Typescript would interpret import such a file as a simple string. I've been following this example.
However, when I import the schema file in my project:
import someSchemaUri from "./schemas/some-name.schema.json";
// ...
uri = someSchemaUri;
I still get type error:
Type '{ ... }' is not assignable to type 'string'.
Changing resolveJsonModule
If I set resolveJsonModule option to false, this problem goes away, but importing package.json from the previous section starts giving an error:
Module 'package.json' was resolved to 'secret/path/package.json', but '--resolveJsonModule' is not used.
How do I configure my project so that Typescript would interpret these files as a string, but at the some don't lose type safety when I import package.json from the previous section?
As I know, there's no way to override json types once --resolveJsonModule was set.
May you consider to disable that flag and write types for package.json manually? It's not time-consuming since you use only one package.json field.
declare module '*.schema.json' {
const uri: string;
export default uri;
}
declare module '*package.json' {
const content: {
version: string;
};
export default content;
}

Gatsby JSON loader not following refs

I need to dereference (swap out JSON References) when importing JSON or YAML files directly into Gatsby pages. Gatsby is pretty good at importing JSON files directly (probably due to some underlying webpack loader), but it doesn't seem to handle JSON refs, a lá "$ref": "../something.json.
For example:
parent.json
{
"someRef" {
"$ref": "./child.json"
}
}
child.json
{
"foo": "bar"
}
index.js
import {SomeJson} from './parent.json'
console.log(SomeJson)
// Expected output: {someRef: {foo: bar}}
// Actual output: {someRef: {$ref: './child.json'}}
I figured that perhaps the default JSON loader being used by Gatsby doesn't allow for JSON References. Fine. But couldn't the webpack configuration be extended to try and add this functionality? Here's my attempt:
gatsby-node.js
exports.onCreateWebpackConfig = ({ actions }) => {
actions.setWebpackConfig({
module: {
rules: [
{
test: /\.json$/,
use: [
{
loader: '#cloudflare/json-schema-ref-loader'
}
]
}
]
},
})
}
The #cloudflare/json-schema-ref-loader library is a webpack loader designed to follow refs. so I figured this could be used.
When running gatsby develop, the build fails with:
Unexpected token m in JSON at position 0 while parsing near 'module.exports = {
...'
error Generating development SSR bundle failed
Any help would be greatly appreciated.

Have problem with importing image in react

Hello everyone I have some problems with importing images to my project. I tried before to import image on my old project the way that i did was working but not for that time. I imported image like:
import Fav from '../img/fav.png'
My file path is in src/img/fav.png and I'm trying to import from src/components/App.jsx
So the error I have is :
ERROR in ./img/fav.png 1:0
Module parse failed: Unexpected character '�' (1:0)
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
(Source code omitted for this binary file)
# ./components/App.jsx 3:0-33
# ./entry.jsx
# multi ./entry.jsx
I tried to find some solutinons in the web bu i couldn't find.
Thanks for help
You need a webpack loader to load the image, e.g. file-loader:
{
test: /\.(png|jpg|gif|svg)$/,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'images',
},
},
],
},
The solution was here:
{
test: /\.(png|svg|jpg|gif)$/,
include: path.resolve(__dirname, 'src/assets'),
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]'
}
}
]
}
The path is included by default.

Webpack - Yaml -> JSON -> Extract file

I have a YAML file with a few translations. I need to transform these files into a JSON file. I've tried using yaml-import-loader and json-loader but I get an error.
Here's my setup:
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractEnglish = new ExtractTextPlugin('lang/en.js');
module.exports = {
entry: [
'./src/locales/application.en.yml',
],
output: {
filename: 'english.js',
},
module: {
strictExportPresence: true,
rules: [
{
test: /\.en\.yml$/,
use: extractEnglish.extract({
use: [
// { loader: 'json-loader' },
{
loader: 'yaml-import-loader',
options: {
output: 'json',
},
}],
}),
},
],
},
plugins: [
extractEnglish,
],
};
And the error I get:
Users/xxx/Documents/Project/node_modules/extract-text-webpack-plugin/dist/index.js:188
chunk.sortModules();
^
TypeError: chunk.sortModules is not a function
at /Users/xxx/Documents/Project/node_modules/extract-text-webpack-plugin/dist/index.js:188:19
Same error whether or not the json-loader is commented or not.
I really don't understand what is going wrong.
Versions:
"webpack": "2.6.1",
"extract-text-webpack-plugin": "^3.0.0",
"json-loader": "^0.5.7",
Not sure if this will help your situation but I recently found a solution to my i18n loading problem. I do this to extract YAML into JSON files upfront as I use angular-translate and needed to load files dynamically and on-demand. I avoid extract-text-webpack-plugin and use only loaders: file-loader and yaml-loader.
First I setup the import of my .yaml files near the beginning of source (in my case a specific chain of import files for webpack to process)
import "./i18n/en.user.yaml";
I updated webpack config to translate YAML to JSON and have it available to load dynamically (everything originates from my 'src' directory, hence the context):
rules: [{
test: /.\.yaml$/,
use: [{
loader: 'file-loader',
options: {
name: '[path][name].json',
context: 'src'
}
},{
loader: 'yaml-loader'
}]
}]
This will translate my yaml file(s) and export them to my public directory, in this case at '/i18n/en.user.json'.
Now when angular-translate uploads my configured i18n settings via $http on-demand, it already has the parsed YAML and avoids having to parse it with js-yaml (or similar) on the front end.
A relatively old question, but I found it while searching for a solution to the same problem, so I thought it worth to chip in.
If you're not really using translation files in your code (i.e. you never import and use them directly) then using a Webpack loader is not the most elegant solution (you'd be forced to import them just so that the loader could be triggered and perform the conversion).
An alternative would be to use the CopyWebpackPlugin instead: it supports a transform option, which takes a function receiving the content of the file as a Buffer.
With a YAML parser (like js-yaml) as an additional dependency, adding this to your Webpack configuration would work:
const yaml = require('js-yaml');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
// OTHER WEBPACK CONFIG HERE
plugins: [
new CopyWebpackPlugin({
patterns: [
{
from: 'i18n/**/*',
to: 'i18n/[name].json',
transform(content) {
return Buffer.from(
JSON.stringify(
yaml.load(content.toString('utf8'), {
schema: yaml.JSON_SCHEMA
})
),
'utf8'
)
}
}
]
})
]
}
The i18n folder in the above example would contain your .yml translations.
The Copy plugin would load them, convert them to JSON, and save them in the output folder under i18n/ (as specified by the to option).

Webpack unable to get json file

I am new to Webpack and I am having a hard time to understand how I can access the content of my json file being added in entry and loaded using json-loader:
entry :
en: {
`${config.basePaths.tmp}script.js`,
`${config.basePaths.tmp}en.json`
}
},
output: {
publicPath: '/js/',
path: `${config.paths.scripts.dist}`,
filename: `[name].script.js`
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
query: {
presets: ['es2015']
}
},
{
test: /\.coffee$/,
loader: 'coffee-loader'
},
{
test: /\.json$/,
loader: 'json-loader'
}
]
}
The object is added to my output file (en.script.js) but I have no clue how to access it... It looks like this:
function(module, exports) {
module.exports = {
"en": {
"title": "I love webpack",
"something": "else"
}
};
}
Please help me.
You should not put a JSON file as the entry point. Entry points are meant to be the starting point of your app and if you specify multiple files per entry point it's just to include them in the same bundle, but they don't really interact with each other (see Concepts - Entry Points).
Instead with webpack you can import files that are not JavaScript, such as .json, and if you have an appropriate loader it will turn that into valid JavaScript which you can use just as any other JavaScript you import. So in your script.js (your entry point) you can import the JSON with:
import enJson from './en.json';
Now you can use enJson as you want, which contains the JavaScript representation of en.json. And by the way remove that from your entry, because webpack will figure out which files are used by looking what is imported from your entry point (and all its dependencies).
entry : {
en: `${config.basePaths.tmp}script.js`,
},