Vue set wrong font url in css while packing multi-entries app - vue.js

PROBLEM DESCRIPTION
I am using vue develop a multi-entries app, the project folder is some like:
|- assets
| |- fonts
| | |- a.ttf
| |- styles
| | |- b.css // import ../fonts/a.ttf
|- src
| |- page_one
| | |- App.vue // import ../../assets/styles/b.css
Above project runs well in local deleopment enviroment, but reported 404 for the .ttf resource after deployed on the server. I checked the built product, found that the css font url is incorrect: I got http://<host>/css/fonts/a.ttf, while http://<host>/fonts/a.ttf is the expected URL.
TRACK the CAUSE
After lots of survey, I found above problem is related to the page entry. Since I got a lot pages, and I wanted to separate them into different folders, so the entries are some like:
// vue.config.js
module.exports = {
pages: {
'a/one': {
filename: 'a/one.html',
},
},
};
After built, the folder is like:
|- dist
| |- css
| | |- a
| | | |- one-<hash>.css // import ../fonts/a.ttf
| |- fonts
| | |- a.ttf
ROOT REASON: The pack tool (webpack) output css file in subfoler a/one-<hash>.css, while the url in css file is incorrect. Looks webpack supposed css file is directly placed at css folder.
SOLUTION: DO NOT USE / IN ENTRY. A correct configuration file is like:
// vue.config.js
module.exports = {
pages: {
'a-one': { // JUST DO NOT USE SLASH.
filename: 'a/one.html', // You can use this to build the produced pages intro separate folders
},
},
};
After all, if you use webpack and meet same problem, the reason and solution should be same.

Remove the '/' from the page entry. Correct:
// vue.config.js
module.exports = {
pages: {
'a-one': { // JUST DO NOT USE SLASH.
filename: 'a/one.html', // You can use this to build the produced pages intro separate folders
},
},
};

Related

How to tell Vite to only build a specific component in library mode?

I have a Vue project that is able to load other Vue components bundled as .mjs files. I want to develop all those pluggable components inside a repository but instead of distributing all pluggable components in a single build I want to tell Vite which component to build. If that works I don't need to think about dealing with a Monorepo, Multirepo or something else.
After creating the library project I thought about organizing each plugin into a separate folder in the src directory
.
└── src
├── textWithBlueBackground
| ├── index.ts ( importing "TextWithBlueBackground" and exporting as "Renderer" )
| └── TextWithBlueBackground.vue
└── textWithRedBackground
├── index.ts ( importing "TextWithRedBackground" and exporting as "Renderer" )
└── TextWithRedBackground.vue
The problem is that I need to switch to library mode but I don't know what to pass in there
build: {
lib: {
entry: resolve(__dirname, "./src/index.ts"), // this is wrong
name: "Renderer",
fileName: "renderer",
},
rollupOptions: {
external: ["vue"],
output: {
globals: {
vue: "Vue",
},
},
},
},
After fixing that... Is it possible to tell Vite ( via CLI flag ) to only build a specific sub directory? E.g.
vite build ./src/{folderName}
If that's not possible I could create an index.ts in src
import { Renderer as TextWithBlueBackground } from "./textWithBlueBackground";
import { Renderer as TextWithRedBackground } from "./textWithRedBackground";
export { TextWithBlueBackground, TextWithRedBackground }
but how can I tell Vite to only build a specific component then?
The generated .mjs file should only contain the desired component, preferably as "Renderer" but I think the component name should be fine too.

webpack/vue/nuxt - Map import if file exists (overwrite)

In my current project I am trying to implement the following:
Let's assume the following file structure:
/src/
/src/components/MyComponent.vue
/src/overwrites/components/MyComponent.vue
(in any *.vue file):
import MyComponent from '#/components/MyComponent.vue'.
This import should, if the same file exists in the parallel existing directory "overwrites", import it instead of the one from /src/components/.
To benefit from hot reloading etc, I want to solve this via webpack.
However, how to extend the vue-loader or get in front of it I haven't figured out.
You can use require.context to crawl directory for components without a webpack or vue-loader involved.
For instance you have structure:
.src
+-- components
| +-- MyComponent.vue
+-- overwrites
| +-- components
| | +-- MyComponent.vue
You will put index.js file in every components folder with content:
const requireModule = require.context('./', false, /\.vue$/)
requireModule.keys().forEach(fileName => {
if (fileName === './index.js') return;
const moduleName = pascalCase(
fileName.replace(/(\.\/|\.vue)/g, '')
);
components[moduleName] = requireModule(fileName)
});
export default components;
Then you will be able to import those index.js files in root component file like:
import components from './components/index.js';
export default {
components: components,
// ...
}
It will load all vue files from components directory. It will solve the issue of hot reloading.
Though, you will have to manage loading of duplicated components on your own, probably with Object.assing like:
import components from './components/index.js';
import {components as overwrites} from './overwrites/components/index.js';
export default {
components: Object.assign({}, components, overwrites),
// ...
}
Duplicated components will be substituted.
I solved the problem with a custom webpack resolver. Similar to this one:
https://github.com/hollandThomas/webpack-custom-resolver/blob/master/StyleResolverPlugin.js
However, I check for ".vue" instead of ".js" and then I substitute the path instead of the filename.

Defining sub routes in components

I want to build a vue application with many modules. Lets say for an online shop we need modules for customers, products, stock inventory, orders, invoices. For every model we need CRUD functions (and some more).
I would prefer a structure, where I have a component for each these modules. And each module component has sub components for list, create, update, read, delete.
|- products/
| |- index.vue
| |- list.vue
| |- add.vue
| |- edit.vue
| |- view.vue
| |- delete.vue
|- customers/
| |- index.vue
| |- list.vue
| |- ...
How can I define the sub routes (children) for each module in the module (index.vue) itself and not in the main router file? Later I want to be able to share certain URLs like
https://domain.tld/products/view/12345
https://domain.tld/products/edit/12345
It can easily be done. Although it could be discussed whether it should be done or not - it does not really change anything, except possibly reducing the verbosity of the main router file. (In any case, the router definition must have all routes in it, so the difference is merely on the aesthetic side)
Routes are simply Javascript objects - why not doing it like below
In index.vue
const productRoutes = [
{
name: 'view',
path: 'view',
component: productView
},
{
name: 'add',
path: 'add',
component: productAdd
},
{
name: 'edit',
path: 'edit',
component: productEdit
},
]
in the router file
const routes = [
{
name: 'products',
path: '/products',
component: products,
children: productRoutes
}
]
const myRouter = new VueRouter({
routes
})
You need to of course add the appropriate import statements - you'll need
these anyway as the router always needs a reference to the components listed.
Components will then simply be defined by their option object, shown as productAdd, productView, productEdit above.

jest projects different setupfiles for each project not working

My file structure is something like:
Product/
|- httpdocs/
|- jest.config.js
|- modules/
|- modules1/
|- jest.config.js
|- modules2/
|- jest.config.js
|- modules3/
|- jest.config.js
In each jest.config.js under the modules I have some configuration for that specific module like: setupFiles: ['<rootDir>/testHelpers/setup.js'].
In my top jest.config.js (under httpdocs) I have defined my different projects:
projects: [
'<rootDir>/modules/module1',
'<rootDir>/modules/module2',
'<rootDir>/modules/module3'
]
When I run jest under httpdocs, the tests fail because the setupfiles (and other configuration) are ignored inside my module/jest.config.js files.
When I run jest under module1, all the tests succeed
Am I doing something wrong or does the option projects not work like this?
-------- EDIT 1 --------
So I restructered my configs like #cimenx suggested.
Product/
|- jest.config.js
|- httpdocs/
|- modules/
|- modules1/
|- foo/
|- bar/
|- foobar.js
|- foobar.test.js
|- modules2/
|- ...
my jest.config.js file looks like this:
module.exports = {
rootDir: './httpdocs/modules',
testPathIgnorePatterns: ['/node_modules/', '/smsc/'],
projects: [
{
displayName: 'module1',
testMatch: ['<rootDir>/module1/*.test.js']
},
{
displayName: 'module2',
testMatch: ['<rootDir>/module2/*.test.js']
}
]
};
At the moment the issue is that jest cannot find any tests inside my modules.
-------- SOLUTION --------
While I was writing my EDIT 1, I tried some other configs...
Apparently my <rootDir> is always the directory where my jest.config.js file is in.
The solution for me was to write the whole path from the config file to the modules without the option rootDir: './some/path'
module.exports = {
projects: [
{
displayName: 'module1',
testMatch: ['<rootDir>/httpdocs/modules/module1/**/*.test.js']
},
{
displayName: 'module2',
testMatch: ['<rootDir>/httpdocs/modules/module2/**/*.test.js']
}
]
};
Thanks for the help!
Probably you should remove all jest.config.js on each modules and rewrite the Product/httpdocs/jest.config.js to be something like this:
module.exports = {
projects: [
{
displayName: "modules1",
setupTestFrameworkScriptFile: '<rootDir>/modules/modules1/jest.setup.js',
/*
Jest config that is specific for modules1
*/
testMatch: ["<rootDir>/modules/modules1/*.spec.js"],
},
{
displayName: "modules2",
setupTestFrameworkScriptFile: '<rootDir>/modules/modules2/jest.setup.js',
/*
Jest config that is specific for modules2
*/
testMatch: ["<rootDir>/modules/modules2/*.spec.js"]
}
]
}

Intern client.js does not use the packages definition from the config file, so cannot resolve dojo/_base/declare

I've been fighting with Intern for quite a while, to test both server code (following these recommendations) and client code (tradionnal app, as defined on this project of mine, for example).
The Intern config file contains:
loader: {
packages: [
{ name: 'dojo', location: './libs/dojo' },
{ name: 'server', location: './server' }
]
},
However, the location of the dojo package is always ignored. The reported error is:
$ node node_modules/intern/client.js config=intern suites=server/model/tests/News
Defaulting to "console" reporter
Error: Failed to load module dojo/_base/declare from <root>/dojo/_base/declare.js (parent: server/model/Ne
ws)
at <root>\node_modules\intern\node_modules\dojo\dojo.js:742:12
at fs.js:207:20
at Object.oncomplete (fs.js:107:15)
I redacted for the <root> part to simplify the output.
My current workaround is to copy the dojo folder at the <root> level but that's inconvenient...
My current folder structure is:
<root>
|- client
|- libs
| |- dojo
| |- ...
|- node_modules
| |- grunt
| |- intern
| |- ...
|- server
|- dao
| |- tests
|- model
| |- tests
|- ...
Where am I wrong?
Update: Everywhere I read (like here), the configuration is specified as a MID, not as a filename with an extension. When I run my command with "config=intern.js" the configuration is correctly processed (I've hacked "client.js" to log the config content). Note: I'm running Node.js/Intern on a Windows machine...
Additional information: Here is the minimum content required to process my tests.
define({
loader: {
packages: [
{ name: 'dojo', location: './libs/dojo' },
{ name: 'server', location: './server' }
]
},
suites: [ 'server/allTests' ]
});
The issue I faced is related to the loader:
If the config file intern.js is at the root level, the command MUST contain the extension: config=intern.js;
If the config file is in a subfolder like tests then the extension MUST be omitted in the command: config=tests/intern.
This happens in intern/client.js, line 38, with the call to the Node.js require() function.