How to output .html to the root of the dist folder when building a project? - vite

When developing, html files are in the “pages” folder, how to move them to the dist/ root when building
rollupOptions: {
input: {
...Object.fromEntries(
glob.sync(resolve(root, 'pages', '*.html')).map((filepath) => {
const { base, name } = parse(filepath);
return [name, resolve(root, 'pages', base)];
})
),
main: resolve(root, 'index.html'),
},
output: {
assetFileNames: ({ name }) => {
let directory = '';
if (/\.woff2?/.test(name)) {
directory = 'fonts';
}
directory += directory ? '/' : '';
return `assets/${directory}[name][extname]`;
},
entryFileNames: '[name].js',
chunkFileNames: 'assets/[name].js',
},
},

Related

How add not imported image to output build with vite?

I have an app folder with some images that are used by the external script and I need to include those images in the dist build folder.
I tried to log files that go to output and those images are not included. I tried to add assetsInclude property but seems that property is not for that purpose.
How can I include some specific images in dist folder that aren't imported explicitly ?
Here is my vite.config.js file.
import { resolve, parse } from 'path';
import { defineConfig } from 'vite';
export default defineConfig({
base: '/',
root: resolve(__dirname, 'app'),
assetsInclude: ['/app/images/externalImage.png'],
build: {
emptyOutDir: true,
rollupOptions: {
output: {
dir: './dist',
assetFileNames: (asset) => {
console.log(parse(asset.name).name);
if (parse(asset.name).name === 'externalImage') {
return "images/src/[name][extname]";
}
return "assets/[name].[hash][extname]";
}
},
},
},
});
In my js file which is included as a module inside the HTML file, I added string that you can see below. Here is details of how to expose the current module URL.
app/js/app.js
new URL("../images/src/externalImage.png", import.meta.url);
Also changed a bit config - added outDir prop:
import { resolve, parse } from 'path';
import { defineConfig } from 'vite';
export default defineConfig({
base: '/',
root: resolve(__dirname, 'app'),
build: {
outDir: '../dist',
emptyOutDir: true,
rollupOptions: {
output: {
assetFileNames: (asset) => {
if (parse(asset.name).name === 'externalImage') {
return "images/src/[name][extname]";
}
return "assets/[name].[hash][extname]";
}
},
},
},
});

How to read the .ts configuration file from the root of the project in the npm package (ESM)

How can I read the configuration file (e.g. mypkg.config.ts) from the root of the project in my npm module built on ESM?
I found this, and figured out how to do it for .json, but not for .ts.
After a few hours of searching, I found what I needed in the sources of Vite.
All you have to do is convert your configuration file into JavaScript using esbuild for example, and then import it using:
const config = await import(`file://${absolutePathToTranspiledConfig}`)
And then just delete the generated JavaScript file.
Specifically, Vite uses the following transpilation script:
await build({
entryPoints: [/*path to config with .ts extension*/],
bundle: true,
minify: true,
platform: 'node',
outfile: /*path to transpiled config*/,
sourcemap: 'inline',
metafile: true,
format: 'esm',
plugins: [
{
name: 'externalize-deps',
setup(build) {
build.onResolve({ filter: /.*/ }, args => {
const id = args.path
if (id[0] !== '.' && !path.isAbsolute(id)) {
return {
external: true
}
}
})
}
},
{
name: 'replace-import-meta',
setup(build) {
build.onLoad({ filter: /\.[jt]s$/ }, async args => {
const contents = await fs.readFile(args.path, 'utf8')
return {
loader: args.path.endsWith('.ts') ? 'ts' : 'js',
contents: contents
.replace(
/\bimport\.meta\.url\b/g,
JSON.stringify(`file://${args.path}`)
)
.replace(
/\b__dirname\b/g,
JSON.stringify(path.dirname(args.path))
)
.replace(/\b__filename\b/g, JSON.stringify(args.path))
}
})
}
}
]
})

Why does webpack + pug generate an Entrypoint undefined = ./index.html error?

The essence of the question is this: there is a build on webpack, everything works fine with one exception: when changing PUG files.
the project is rebuilt, but the content is not updated in the browser.
When building it produces an error: Entrypoint undefined = ./index.html
const path = require('path');
const fs = require('fs');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin');
const PATHS = {
src: path.join(__dirname, './src'),
dist: path.join(__dirname, './dist'),
assets: 'assets/',
pages: function () { return `${this.src}/pug/` }
}
// const PAGES_DIR = PATHS.src
const PAGES = fs.readdirSync(PATHS.pages()).filter(fileName => fileName.endsWith('.pug'));
const isDev = process.env.NODE_ENV === 'development'
const isProd = !isDev
const optimization = () => {
const config = {
splitChunks: {
chunks: 'all'
}
}
if (isProd) {
config.minimizer = [
new OptimizeCssAssetWebpackPlugin(),
new TerserWebpackPlugin()
]
}
return config
}
const filename = ext => isDev ? `[name].${ext}` : `[name].[hash].${ext}`
const cssLoaders = extra => {
const loaders = [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: isDev,
reloadAll: true
},
},
'css-loader'
]
if (extra) {
loaders.push(extra)
}
return loaders
}
const babelOptions = preset => {
const opts = {
presets: [
'#babel/preset-env'
],
plugins: [
'#babel/plugin-proposal-class-properties'
]
}
if (preset) {
opts.presets.push(preset)
}
return opts
}
const jsLoaders = () => {
const loaders = [{
loader: 'babel-loader',
options: babelOptions()
}]
if (isDev) {
loaders.push('eslint-loader')
}
return loaders
}
const plugins = () => {
const base = [
new CleanWebpackPlugin(),
new CopyWebpackPlugin([
{ from: `${PATHS.src}/${PATHS.assets}img`, to: `${PATHS.assets}img` },
{ from: `${PATHS.src}/${PATHS.assets}fonts`, to: `${PATHS.assets}fonts` },
{ from: `${PATHS.src}/static`, to: '' },
]),
new MiniCssExtractPlugin({
filename: filename('css')
}),
...PAGES.map(page => new HTMLWebpackPlugin({
template: `${PATHS.pages()}/${page}`,
filename: `./${page.replace(/\.pug/,'.html')}`,
}))
]
return base
}
module.exports = {
context: PATHS.src,
mode: process.env.NODE_ENV,
entry: {
app: PATHS.src,
},
output: {
filename: filename('js'),
path: PATHS.dist
},
resolve: {
extensions: ['.js', '.json', '.png'],
alias: {
'#': PATHS.src,
}
},
optimization: optimization(),
devServer: {
hot: isDev
},
devtool: isDev ? 'source-map' : '',
plugins: plugins(),
module: {
rules: [
{
test: /\.pug$/,
loader: 'pug-loader',
options: {
pretty: isProd
}
},
{
test: /\.css$/,
use: cssLoaders()
},
{
test: /\.s[ac]ss$/,
use: cssLoaders('sass-loader')
},
{
test: /\.(png|jpg|svg|gif)$/,
use: ['file-loader']
},
{
test: /\.(ttf|woff|woff2|eot)$/,
use: ['file-loader']
},
{
test: /\.xml$/,
use: ['xml-loader']
},
{
test: /\.csv$/,
use: ['csv-loader']
},
{
test: /\.js$/,
exclude: /node_modules/,
use: jsLoaders()
}
]
}
}
Project structure:
enter image description here
Have you tried html-webpack-pug-plugin?
npm i html-webpack-pug-plugin
Replace this:
const plugins = () => {
const base = [
//..
...PAGES.map(page => new HTMLWebpackPlugin({
template: `${PATHS.pages()}/${page}`,
filename: `./${page.replace(/\.pug/, '.html')}`,
}))
]
//...
With this:
const plugins = () => {
const base = [
//..
new HtmlWebpackPugPlugin(),
new HtmlWebpackPlugin({
template: './src/pug/index.pug',
filename: 'index.pug',
})
]
//...
The plugin will copy the main index.pug file into the dist directory with reference to js and css files.
The pug files in static directory should then load the main template file like this:
extends ../../dist/index.pug
I have solved this problem with additional package chokidar.
i use next code:
const chokidar = require('chokidar');
...
devServer: {
hot: true,
overlay: {
warnings: false,
errors: true
},
before(app, server) {
chokidar.watch([
`${PATHS.src}/**/*.pug`
]).on('all', function() {
server.sockWrite(server.sockets, 'content-changed');
})
}
}
...

Webpack 4 unable to built production for web

I am breaking my head, trying to understand why this production build is not working on the browser.
So basically I have a development config that works flawlessly, but the production build keeps displaying for some weird reason Error: Minified React error #200; visit https://reactjs.org/docs/error-decoder.html?invariant=200 for the full message or use the non-minified dev environment for full errors and additional helpful warnings. on the console.
Any help on this would be much appreciated.
Here is my folder structure
package.json
"build": "webpack --config=config/webpack.config.js --env production --progress",
"start": "webpack-dev-server --config=config/webpack.config.js --env development --open"
And webpack.config.js (I have omitted the developer config since it works fine )
...
// Paths
getPaths = ({
sourceDir = '../app',
distDir = '../dist',
staticDir = 'static',
images = 'images',
fonts = 'fonts',
scripts = 'scripts',
styles = 'styles'} = {}) => {
const assets = { images, fonts, scripts, styles }
return Object.keys(assets).reduce((obj, assetName) => {
const assetPath = assets[assetName]
obj[assetName] = !staticDir ? assetPath : `${staticDir}/${assetPath}`
return obj
},{
app: path.join(__dirname, sourceDir),
dist: path.join(__dirname, distDir),
staticDir
})
},
paths = getPaths(),
publicPath = '',
// Main module
commonConfig = merge([{
context: paths.app,
resolve: {
unsafeCache: true,
symlinks: false
},
entry: [`${paths.app}/scripts/index.jsx`, `${paths.app}/styles/styles.scss`],
output: { path: paths.dist, publicPath },
plugins: [
new HtmlPlugin(),
]
},
load.Html(),
})
]),
// Build
productionConfig = merge([
{
mode: 'production'
},
load.Scripts({
include: paths.app,
exclude: path.resolve(__dirname, 'node_modules'),
options: {
configFile: path.resolve(__dirname, 'babel.config.js'),
}
}),
load.ExtractCSS({
include: paths.app,
options: {
filename: `${paths.styles}/[name].min.[contenthash:8].css`,
chunkFilename: `${paths.styles}/[id].[contenthash:8].css`,
publicPath: '../'
}
})
]),
// Merge module
module.exports = env => {
process.env.NODE_ENV = env
return merge(commonConfig, env === 'production' ? productionConfig : developmentConfig
)
}
And finally the referenced modules webpack.modules.js
exports.Html = () => ({
module: {
rules: [
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
}
]
}
]
}
})
exports.MinifyCSS = ({ options }) => ({
optimization: {
minimizer: [
new OptimizeCSSAssetsPlugin({
cssProcessorOptions: options,
canPrint: true // false for analyzer
})
]
}
})
exports.ExtractCSS = ({ include, exclude, options } = {}) => ({
module: {
rules: [{
test: /\.scss$/,
include,
exclude,
use: [
{ loader: MiniCssExtractPlugin.loader, options: { publicPath: '../../' } },
'css-loader',
{ loader: 'postcss-loader', options: { plugins: () => [require('autoprefixer')] }},
'fast-sass-loader'
]
}]
},
plugins: [ new MiniCssExtractPlugin(options) ]
})
exports.Scripts = ({ include, exclude, options } = {}) => ({
module: {
rules: [{
test: /\.(js|jsx)$/,
include,
exclude,
use: [{ loader: 'babel-loader', options }]
}]
}
})
After runing npm run build when I open the website on https://localhost/React/Transcript/dist/ I get:
Error: Minified React error #200; visit https://reactjs.org/docs/error-decoder.html?invariant=200 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
Thanks to everyone on the comment section for helping me find the problem, it turns out that I had to remove the module: { noParse: /\.min\.js/ } from the common config and add new HtmlPlugin({ template: './index.html'}) instead of just new HtmlPlugin()

Why get require('fs') is undefined in r.js

I want append some string from file use fs.readSyncFile(), but I get a undefined.
r.js -o build.js
({
appDir: ".",
baseUrl: './assets/js',
dir: 'build',
modules: [
{name: 'init'}
],
paths: {
'init': 'app/init'
},
onBuildRead: function (moduleName, path, contents) {
if(moduleName == 'init') {
console.log('--------------' + require('fs'));//undefined
}
return contents.replace("'/assets/js/main.js',", "");
},
})

Resources